1#include "assertion_logger.h"
2
3#include <base/lock.h>
4#include <base/logger.h>
5#include <base/system.h>
6
7#include <engine/shared/ringbuffer.h>
8#include <engine/storage.h>
9
10class CAssertionLogger : public ILogger
11{
12 struct SDebugMessageItem
13 {
14 char m_aMessage[1024];
15 };
16
17 CLock m_DbgMessageMutex;
18 CStaticRingBuffer<SDebugMessageItem, sizeof(SDebugMessageItem) * 64, CRingBufferBase::FLAG_RECYCLE> m_DbgMessages;
19
20 char m_aAssertLogPath[IO_MAX_PATH_LENGTH];
21 char m_aGameName[256];
22
23 void Dump() REQUIRES(!m_DbgMessageMutex);
24
25public:
26 CAssertionLogger(const char *pAssertLogPath, const char *pGameName);
27 void Log(const CLogMessage *pMessage) override REQUIRES(!m_DbgMessageMutex);
28 void GlobalFinish() override REQUIRES(!m_DbgMessageMutex);
29};
30
31void CAssertionLogger::Log(const CLogMessage *pMessage)
32{
33 if(m_Filter.Filters(pMessage))
34 {
35 return;
36 }
37 const CLockScope LockScope(m_DbgMessageMutex);
38 SDebugMessageItem *pMsgItem = (SDebugMessageItem *)m_DbgMessages.Allocate(Size: sizeof(SDebugMessageItem));
39 str_copy(dst&: pMsgItem->m_aMessage, src: pMessage->m_aLine);
40}
41
42void CAssertionLogger::GlobalFinish()
43{
44 if(dbg_assert_has_failed())
45 {
46 Dump();
47 }
48}
49
50void CAssertionLogger::Dump()
51{
52 char aAssertLogFile[IO_MAX_PATH_LENGTH];
53 char aDate[64];
54 str_timestamp(buffer: aDate, buffer_size: sizeof(aDate));
55 str_format(buffer: aAssertLogFile, buffer_size: std::size(aAssertLogFile), format: "%s%s_assert_log_%s_%d.txt", m_aAssertLogPath, m_aGameName, aDate, pid());
56 const CLockScope LockScope(m_DbgMessageMutex);
57 IOHANDLE FileHandle = io_open(filename: aAssertLogFile, flags: IOFLAG_WRITE);
58 if(FileHandle)
59 {
60 auto *pIt = m_DbgMessages.First();
61 while(pIt)
62 {
63 io_write(io: FileHandle, buffer: pIt->m_aMessage, size: str_length(str: pIt->m_aMessage));
64 io_write(io: FileHandle, buffer: "\n", size: 1);
65
66 pIt = m_DbgMessages.Next(pCurrent: pIt);
67 }
68
69 io_sync(io: FileHandle);
70 io_close(io: FileHandle);
71 }
72}
73
74CAssertionLogger::CAssertionLogger(const char *pAssertLogPath, const char *pGameName)
75{
76 str_copy(dst&: m_aAssertLogPath, src: pAssertLogPath);
77 str_copy(dst&: m_aGameName, src: pGameName);
78}
79
80std::unique_ptr<ILogger> CreateAssertionLogger(IStorage *pStorage, const char *pGameName)
81{
82 char aAssertLogPath[IO_MAX_PATH_LENGTH];
83 pStorage->GetCompletePath(Type: IStorage::TYPE_SAVE, pDir: "dumps/", pBuffer: aAssertLogPath, BufferSize: sizeof(aAssertLogPath));
84 return std::make_unique<CAssertionLogger>(args&: aAssertLogPath, args&: pGameName);
85}
86