Emu/source/common/debug.h
2025-09-06 21:20:01 -05:00

115 lines
2.7 KiB
C++

// Copyright (C) 2007-2025 EQ2EMulator
// Licensed under GPL v3
#pragma once
#include <cstdio>
#include <cstdarg>
#include <cstdint>
#include <iostream>
#include <mutex>
// Debug Levels
/*
1 = Normal
3 = Some extended debug info
5 = Light DETAIL info
7 = Heavy DETAIL info
9 = DumpPacket/PrintPacket
You should use even numbers too, to define any subset of the above basic template
*/
#ifndef EQDEBUG
#define EQDEBUG 1
#endif
#ifndef ThrowError
void CatchSignal(int);
#if defined(CATCH_CRASH) || defined(_EQDEBUG)
#define ThrowError(errstr) { \
std::cout << "Fatal error: " << errstr << " (" << __FILE__ << ", line " << __LINE__ << ")" << std::endl; \
LogWrite(WORLD__ERROR, 0, "Debug", "Thrown Error: %s (%s:%i)", errstr, __FILE__, __LINE__); \
throw errstr; \
}
#else
#define ThrowError(errstr) { \
std::cout << "Fatal error: " << errstr << " (" << __FILE__ << ", line " << __LINE__ << ")" << std::endl; \
LogWrite(WORLD__ERROR, 0, "Debug", "Thrown Error: %s (%s:%i)", errstr, __FILE__, __LINE__); \
CatchSignal(0); \
}
#endif
#endif
#define DebugBreak() if(0) {}
class EQEMuLog
{
public:
EQEMuLog();
~EQEMuLog();
enum LogIDs
{
Status = 0, //this must stay the first entry in this list
Normal,
Error,
Debug,
Quest,
Commands,
MaxLogID
};
// Callbacks called for each log entry
using msgCallbackBuf = void (*)(LogIDs id, const char* buf, std::int8_t size, std::int32_t count);
using msgCallbackFmt = void (*)(LogIDs id, const char* fmt, va_list ap);
void SetAllCallbacks(msgCallbackFmt proc);
void SetAllCallbacks(msgCallbackBuf proc);
void SetCallback(LogIDs id, msgCallbackFmt proc);
void SetCallback(LogIDs id, msgCallbackBuf proc);
bool writebuf(LogIDs id, const char* buf, std::int8_t size, std::int32_t count);
bool write(LogIDs id, const char* fmt, ...);
bool Dump(LogIDs id, std::uint8_t* data, std::int32_t size, std::int32_t cols = 16, std::int32_t skip = 0);
private:
bool open(LogIDs id);
bool writeNTS(LogIDs id, bool dofile, const char* fmt, ...); // no error checking, assumes is open, no locking, no timestamp, no newline
std::mutex MOpen;
std::mutex MLog[MaxLogID];
FILE* fp[MaxLogID];
/* LogStatus: bitwise variable
1 = output to file
2 = output to stdout
4 = fopen error, dont retry
8 = use stderr instead (2 must be set)
*/
std::int8_t pLogStatus[MaxLogID];
msgCallbackFmt logCallbackFmt[MaxLogID];
msgCallbackBuf logCallbackBuf[MaxLogID];
};
#ifdef _EQDEBUG
class PerformanceMonitor
{
public:
PerformanceMonitor(std::int64_t* ip)
{
p = ip;
QueryPerformanceCounter(&tmp);
}
~PerformanceMonitor()
{
LARGE_INTEGER tmp2;
QueryPerformanceCounter(&tmp2);
*p += tmp2.QuadPart - tmp.QuadPart;
}
LARGE_INTEGER tmp;
std::int64_t* p;
};
#endif