Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Trace.inl
1
2/*
3 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
4 */
5
6#include <filesystem>
7#include <mutex>
8
9CompileTimeFlagChecker_HEADER (Stroika::Foundation::Debug, qTraceToFile, qStroika_Foundation_Debug_TraceToFile);
10CompileTimeFlagChecker_HEADER (Stroika::Foundation::Debug, qDefaultTracingOn, qStroika_Foundation_Debug_DefaultTracingOn);
11
14
15namespace Stroika::Foundation::Debug {
16
17 namespace Private_ {
18 struct ModuleInit_ final {
19 ModuleInit_ () noexcept;
20 ~ModuleInit_ ();
21 };
22 const inline ModuleInit_ _MI_;
23 }
24
25 class Private_::Emitter final {
26 public:
27 Emitter () = default;
28 Emitter (const Emitter&) = delete;
29
30 public:
31 static Emitter& Get () noexcept;
32
33#if qStroika_Foundation_Debug_TraceToFile
34 public:
35 static filesystem::path GetTraceFileName ();
36#endif
37
38 public:
39 /**
40 * \note DbgTrace() is NOT a cancelation point, so you can call this freely without worrying about Throw (ThreadAbortException) etc
41 */
42 [[deprecated ("Since Stroika v3.0d6 - use _f format strings")]] void EmitTraceMessage (const char* format, ...) noexcept;
43 [[deprecated ("Since Stroika v3.0d6 - use _f format strings")]] void EmitTraceMessage (const wchar_t* format, ...) noexcept;
44
45 template <typename CHAR_T, Common::StdCompat::formattable<wchar_t>... Args>
46 nonvirtual void EmitTraceMessage (Characters::FormatString<CHAR_T> fmt, Args&&... args) noexcept
47 {
48 try {
49 EmitTraceMessage_ (fmt.get (), Common::StdCompat::make_wformat_args (args...));
50 }
51 catch (...) {
52 }
53 }
54
55 private:
56 nonvirtual TraceLastBufferedWriteTokenType EmitTraceMessage_ (size_t bufferLastNChars, wstring_view format,
57 Common::StdCompat::wformat_args&& args) noexcept;
58 nonvirtual void EmitTraceMessage_ (wstring_view format, Common::StdCompat::wformat_args&& args) noexcept;
59 nonvirtual void EmitTraceMessage_ (string_view format, Common::StdCompat::format_args&& args) noexcept;
60 nonvirtual void EmitTraceMessage_ (const wstring& raw) noexcept;
61
62 public:
63 // if the last write matches the given token (no writes since then) and the timestamp is unchanged, abandon
64 // the buffered characters and return true. Else flush(write) them, and return false.
65 nonvirtual bool UnputBufferedCharactersForMatchingToken (TraceLastBufferedWriteTokenType token);
66
67 template <typename CHARTYPE>
68 nonvirtual void EmitUnadornedText (const CHARTYPE* p);
69
70 private:
71 // This is the same as EmitTraceMessage_ - but it takes a plain string - and assumes the caller does any 'sprintf' stuff...
72 template <typename CHARTYPE>
73 nonvirtual TraceLastBufferedWriteTokenType DoEmitMessage_ (size_t bufferLastNChars, const CHARTYPE* p, const CHARTYPE* e);
74
75 private:
76 size_t fLastNCharBufCharCount_{0}; // len of valid data in fLastNCharBuf_CHAR_ or fLastNCharBuf_WCHAR_
77 char fLastNCharBuf_CHAR_[10]; // always filled in before used, so no need to initialize - NOT nul-terminated(see fLastNCharBufCharCount_)
78 wchar_t fLastNCharBuf_WCHAR_[10];
79 bool fLastNCharBuf_WCHARFlag_{false}; // determines (if fLastNCharBufCharCount_!=0) which buffer CHAR or WCHAR to use
80 TraceLastBufferedWriteTokenType fLastNCharBuf_Token_{0};
81 Time::DisplayedRealtimeClock::time_point fLastNCharBuf_WriteTickcount_{};
82
83 nonvirtual void BufferNChars_ (size_t nChars, const char* p);
84 nonvirtual void BufferNChars_ (size_t nChars, const wchar_t* p);
85
86 private:
87 nonvirtual void FlushBufferedCharacters_ ();
88
89 private:
90 nonvirtual void DoEmit_ (const char* p) noexcept;
91 nonvirtual void DoEmit_ (const wchar_t* p) noexcept;
92 nonvirtual void DoEmit_ (const char* p, const char* e) noexcept;
93 nonvirtual void DoEmit_ (const wchar_t* p, const wchar_t* e) noexcept;
94
95 private:
96 friend class Debug::TraceContextBumper;
97 };
98
99 namespace Private_ {
100 template <typename ARRAY_TYPE, size_t SIZE_OF_ARRAY>
101 inline constexpr size_t NEltsOf ([[maybe_unused]] const ARRAY_TYPE (&arr)[SIZE_OF_ARRAY])
102 {
103 return SIZE_OF_ARRAY;
104 }
105 }
106 /*
107 ********************************************************************************
108 ******************************* TraceContextBumper *****************************
109 ********************************************************************************
110 */
112 {
113#if qStroika_Foundation_Debug_DefaultTracingOn
114 IncCount_ ();
115#endif
116 }
117 template <typename CHAR_T>
118 inline TraceContextBumper::TraceContextBumper ([[maybe_unused]] const CHAR_T* contextName) noexcept
119 requires (same_as<CHAR_T, char> or same_as<CHAR_T, wchar_t>)
120#if qStroika_Foundation_Debug_DefaultTracingOn
121 : TraceContextBumper{cvt2WChartArrayTrunc_ (contextName)}
122#endif
123 {
124 }
125 template <typename CHAR_T, typename FCHAR_T, typename... ARGS>
126 TraceContextBumper::TraceContextBumper ([[maybe_unused]] const CHAR_T* contextName,
127 [[maybe_unused]] Characters::FormatString<FCHAR_T> fmt, [[maybe_unused]] ARGS&&... args) noexcept
128 requires ((same_as<CHAR_T, char> or same_as<CHAR_T, wchar_t>) and (same_as<FCHAR_T, char> or same_as<FCHAR_T, wchar_t>))
129#if qStroika_Foundation_Debug_DefaultTracingOn
130 : TraceContextBumper{cvt2WChartArrayTrunc_ (contextName), ProcessFmtString_ (fmt, forward<ARGS> (args)...)}
131#endif
132 {
133 }
134#if !qStroika_Foundation_Debug_DefaultTracingOn
135 inline TraceContextBumper::TraceContextBumper ([[maybe_unused]] const wchar_t* contextName, [[maybe_unused]] const wchar_t* extraFmt, ...) noexcept
136 {
137 }
138#endif
139#if qStroika_Foundation_Debug_DefaultTracingOn
140 template <typename CHAR_T, typename... ARGS>
141 auto TraceContextBumper::ProcessFmtString_ (Characters::FormatString<CHAR_T> fmt, ARGS&&... args) noexcept -> CHAR_ARRAY_T
142 requires (same_as<CHAR_T, char> or same_as<CHAR_T, wchar_t>)
143 {
144 try {
145 wstring r = Common::StdCompat::vformat (qStroika_Foundation_Characters_FMT_PREFIX_::wstring_view{fmt.get ()},
146 Common::StdCompat::make_wformat_args (args...));
147 size_t len = min<size_t> (r.size (), kMaxContextNameLen_);
148 CHAR_ARRAY_T result;
149 // Dont call Memory::Span here - but reproduce in loop to avoid deadly embrace
150 char_traits<wchar_t>::copy (result.data (), r.data (), len);
151 // for (size_t i = 0; i < len; ++i) {
152 // result[i] = static_cast<wchar_t> (r[i]);
153 // }
154 result[len] = '\0'; //char_traits::copy doesn't appear to NUL-terminate
155 return result;
156 }
157 catch (...) {
158 // we are already deep in the guts of DbgTrace stuff - so not much chance of 'logging' this issue ;-)
159 return {};
160 }
161 }
162 template <typename CHAR_T>
163 auto TraceContextBumper::cvt2WChartArrayTrunc_ (span<const CHAR_T> contextName) -> CHAR_ARRAY_T
164 {
165 // Return item with max size kMaxContextNameLen_+1 so we can tell if we need to add ellipsis
166 array<wchar_t, kMaxContextNameLen_ + 1> r;
167 auto ci = contextName.begin ();
168 for (; ci != contextName.end (); ++ci) {
169 size_t i = ci - contextName.begin ();
170 if (i < kMaxContextNameLen_) {
171 r[i] = *ci;
172 }
173 else {
174 break;
175 }
176 }
177 Assert (ci - contextName.begin () <= kMaxContextNameLen_);
178 r[ci - contextName.begin ()] = '\0';
179 return r;
180 }
181 template <typename CHAR_T>
182 auto TraceContextBumper::cvt2WChartArrayTrunc_ (const CHAR_T* contextName) -> CHAR_ARRAY_T
183 {
184 return cvt2WChartArrayTrunc_ (span{contextName, char_traits<CHAR_T>::length (contextName)});
185 }
186#endif
187
188 /*
189 ********************************************************************************
190 ******************************* TraceContextBumper *****************************
191 ********************************************************************************
192 */
193 inline TraceContextSuppressor::TraceContextSuppressor () noexcept
194 {
195 ++tSuppressCnt_;
196 }
197 inline TraceContextSuppressor::~TraceContextSuppressor ()
198 {
199 --tSuppressCnt_;
200 }
201 inline bool TraceContextSuppressor::GetSuppressTraceInThisThread ()
202 {
203 return tSuppressCnt_ > 0;
204 }
205
206}
#define CompileTimeFlagChecker_HEADER(NS_PREFIX, NAME, VALUE)
CompileTimeFlagChecker_HEADER () will generate a LINK ERROR if you ever compile a header with one val...
#define qStroika_Foundation_Debug_TraceToFile
Definition Trace.h:45
Roughly equivalent to std::wformat_string, except that it can be constructed from 'char' string,...