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