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 | |
10 | class 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 | |
25 | public: |
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 | |
31 | void 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 | |
42 | void CAssertionLogger::GlobalFinish() |
43 | { |
44 | if(dbg_assert_has_failed()) |
45 | { |
46 | Dump(); |
47 | } |
48 | } |
49 | |
50 | void 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 | |
74 | CAssertionLogger::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 | |
80 | std::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 | |