ALib C++ Library
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
loxpimpl.cpp
1//##################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6//##################################################################################################
7#include "alib_precompile.hpp"
8#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
9# error "Symbol ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
10#endif
11#if ALIB_C20_MODULES
12 module;
13#endif
14//========================================= Global Fragment ========================================
19//============================================== Module ============================================
20#if ALIB_C20_MODULES
21 module ALib.ALox.Impl;
22 import ALib.ALox;
23 import ALib.Lang;
24 import ALib.EnumOps;
25 import ALib.Strings;
26 import ALib.Strings.Tokenizer;
27 import ALib.Boxing;
28 import ALib.EnumRecords;
29 import ALib.EnumRecords.Bootstrap;
30 import ALib.Variables;
31 import ALib.Camp;
32 import ALib.Camp.Base;
33 import ALib.Bootstrap;
34#else
35# include "ALib.Bootstrap.H"
36# include "ALib.Lang.H"
37# include "ALib.Strings.H"
39# include "ALib.Boxing.H"
41# include "ALib.Variables.H"
42# include "ALib.Camp.H"
43# include "ALib.Camp.Base.H"
44# include "ALib.ALox.H"
45# include "ALib.ALox.Impl.H"
46#endif
47//========================================== Implementation ========================================
48#if !ALIB_SINGLE_THREADED
49# define UNDEFINED_THREAD threads::UNDEFINED
50#else
51# define UNDEFINED_THREAD 0
52#endif
53
55 ALIB_COMMA alib::variables::Priority>, vt_lox_pair_verby_prio )
56
58
59# include "ALib.Lang.CIFunctions.H"
60
61namespace alib { namespace lox { namespace detail {
62
63/// Domain substitution rules.
64struct DomainSubstitutionRule
65{
66 /// Rule types.
67 public: enum class Type
68 {
69 Exact, ///< Exact match.
70 StartsWith, ///< Starts with match.
71 EndsWith, ///< Ends with match.
72 Substring ///< Any substring.
73 };
74
75 Type type; ///< Denotes the type of the rule, depending of what
76 ///< was set in originally as search path
77 NString32 Search; ///< The path to search.
78 NString32 Replacement; ///< The replacement.
79
80 /// Constructor.
81 /// @param s The path to search.
82 /// @param r The replacement.
83 DomainSubstitutionRule( const NString& s, const NString& r ) {
84 Search .DbgDisableBufferReplacementWarning();
85 Replacement.DbgDisableBufferReplacementWarning();
86
87 // get type and adjust given search parameter
88 integer startPos= 0;
89 integer length= s.Length();
90 if ( s.CharAtStart() == '*' ) {
91 ++startPos;
92 --length;
93 if ( s.CharAtEnd() == '*' ) {
94 type= Type::Substring;
95 --length;
96 }
97 else
98 type= Type::EndsWith;
99 } else {
100 if ( s.CharAtEnd() == '*' ) {
101 type= Type::StartsWith;
102 --length;
103 }
104 else
105 type= Type::Exact;
106 }
107 Search._( s, startPos, length );
108
109 // minimum rule check
110 if ( ( ( type == Type::Exact
111 || type == Type::StartsWith )
112 && Search.CharAtStart() != '/'
113 )
114 || ( type == Type::EndsWith
115 && Search.CharAtEnd() == '/'
116 )
117 )
118 Search.Reset(); // illegal rule
119
120
121 Replacement= r;
122 }
123}; // struct DomainSubstitutionRule
124
125
126//==================================================================================================
127/// Implementation struct for class \alib{lox;Lox} following the
128/// \https{Pimpl Idiom,en.cppreference.com/w/cpp/language/pimpl}.
129//==================================================================================================
130struct LoxImpl
131{
132 /// The self contained monotonic allocator, that also contains this struct itself.
133 MonoAllocator& monoAllocator;
134
135 /// A pool allocator that uses #monoAllocator as its source.
136 PoolAllocator poolAllocator;
137
138 /// Snapshot taken before embedding the lox in the #monoAllocator.
139 monomem::Snapshot beforeLox;
140
141 #if !ALIB_SINGLE_THREADED
142 /// A mutex to control parallel access.
143 threads::RecursiveLock Lock;
144 #endif
145
146 /// Counts the number of nested (recursive) acquirements.
147 int AcquirementsCount;
148
149 /// A counter for the quantity of calls. The count includes logs suppressed by
150 /// disabled <em>Log Domain</em> and those suppressed by the optional log condition parameter.
151 integer CntLogCalls =0;
152
153 /// A list of a list of logables used for (recursive) logging.
154 StdVectorMA<BoxesMA*> logableContainers;
155
156 /// A list of a list of logables used for (recursive) internal logging.
157 StdVectorMA<BoxesMA*> internalLogables;
158
159 /// The recursion counter for internal logging.
160 integer internalLogRecursionCounter = 0;
161
162 /// Information about the source code, method, thread, etc. invoking a log call
163 ScopeInfo scopeInfo;
164
165 /// The root domain \"/\". All registered domains become a sub domain of this root.
166 /// If a <em>Sub-Log Domain's Verbosity</em> is not explicitly set, such sub domain inherits
167 /// the verbosity of its parent.
168 Domain* domains;
169
170 /// The root domain for internal <em>Log Domains</em>.
171 Domain* internalDomains;
172
173 /// Scope Domains
174 ScopeStore<NString , true > scopeDomains;
175
176 /// Prefix logables store
177 ScopeStore<PrefixLogable*, true > scopePrefixes;
178
179 /// Log once counters
180 ScopeStore<SSMap<int>* , false> scopeLogOnce;
181
182 /// Log data store
183 ScopeStore<SSMap<Box>* , false> scopeLogData;
184
185 /// Used for tabular output of logger lists
186 integer maxLoggerNameLength =0;
187
188 /// Used for tabular output of logger lists
189 integer maxDomainPathLength;
190
191 /// A key value used in stores if no key is given (global object).
192 const NString noKeyHashKey = "$";
193
194
195 /// The list of domain substitution rules.
196 ListMA<DomainSubstitutionRule> domainSubstitutions;
197
198 /// Flag if a warning on circular rule detection was logged.
199 bool oneTimeWarningCircularDS =false;
200
201 /// Flag used with configuration variable LOXNAME_DUMP_STATE_ON_EXIT.
202 bool loggerAddedSinceLastDebugState =false;
203
204 /// Constructor.
205 /// @param ma The externally created, self-contained monotonic allocator, that also contains
206 /// this instance.
207 /// @param name The lox's name.
208 LoxImpl( MonoAllocator* ma, const NString& name )
209 : monoAllocator ( *ma )
210 , poolAllocator ( monoAllocator )
211 , AcquirementsCount ( 0 )
212 , logableContainers ( monoAllocator )
213 , internalLogables ( monoAllocator )
214 , scopeInfo ( name , monoAllocator )
215 , scopeDomains ( scopeInfo, monoAllocator )
216 , scopePrefixes ( scopeInfo, monoAllocator )
217 , scopeLogOnce ( scopeInfo, monoAllocator )
218 , scopeLogData ( scopeInfo, monoAllocator )
219 , domainSubstitutions( monoAllocator )
220 {
222 LI::init(this);
223 }
224
225 /// Destructor.
226 ~LoxImpl() {
227 // unregister each logger in std domains and remove it in internals
228 for ( int i= domains->CountLoggers() - 1 ; i >= 0 ; --i ) {
229 Logger* logger= domains->GetLogger( i );
230 int ii= internalDomains->GetLoggerNo( logger );
231 if ( ii >= 0 )
232 internalDomains->RemoveLogger( ii );
233 logger->AcknowledgeLox( this, lang::ContainerOp::Remove );
234 }
235
236 // unregister remaining loggers in internal domains
237 for ( int i= internalDomains->CountLoggers() - 1 ; i >= 0 ; --i ) {
238 Logger* logger= internalDomains->GetLogger( i );
239 logger->AcknowledgeLox( this, lang::ContainerOp::Remove );
240 } }
241
242 /// Returns the number of (recursive) acquirements of this \b Lox.
243 /// If greater than \c 1, this is either recursive logging or a user has explicitly
244 /// acquired this lox repeatedly (which is not recommended to do).
245 ///
246 /// @return The number of acquirements.
247 int CountAcquirements() const noexcept { return AcquirementsCount; }
248
249 /// Shortcut to allocate arbitrary objects in #poolAllocator.
250 /// @tparam T The type to allocate.
251 /// @tparam TArgs Types of variadic parameters given with parameter \p{args}.
252 /// Deduced by the compiler.
253 /// @param args Variadic parameters to be forwarded to the constructor of type \p{T}.
254 /// @return The allocated object.
255 template<typename T, typename... TArgs>
256 T* newPO(TArgs&&... args) { return poolAllocator().New<T>(std::forward<TArgs>(args)...); }
257
258 /// Shortcut to delete arbitrary objects in #poolAllocator.
259 /// @tparam T The type to allocate. Deduced by the compiler.
260 /// @param o The allocated object.
261 template<typename T>
262 void deletePO(T* o) { poolAllocator().Delete<T>(o); }
263
264}; // struct LoxImpl
265
266
267#define ASSERT_ACQUIRED ALIB_ASSERT_ERROR( impl->CountAcquirements() >0,"ALOX","Lox not acquired" )
268
269//##################################################################################################
270// Constructors/destructor
271//##################################################################################################
272LoxImpl* LI::Construct(const NString& name) {
273 lang::HeapAllocator ha;
274 MonoAllocator* selfContainedMA= MonoAllocator::Create( ALIB_DBG(nullptr,) ha, 8* 1024 );
275 ALIB_DBG( selfContainedMA->DbgName= NCString(*selfContainedMA, NString128("Lox") << name).Buffer(); )
276 auto snapShot= selfContainedMA->TakeSnapshot();
277 LoxImpl* result= (*selfContainedMA)().New<LoxImpl>( selfContainedMA, name );
278 result->beforeLox= snapShot;
279 return result;
280}
281
282void LI::Destruct( LoxImpl* impl ) {
283 auto& ma= impl->monoAllocator;
284 impl->~LoxImpl();
285 lang::Destruct(ma); // just destruct, as this is self-contained
286}
287
288const NString& LI::GetName(LoxImpl* impl) { return impl->scopeInfo.loxName; }
289
290integer& LI::GetLogCounter(LoxImpl* impl) { return impl->CntLogCalls; }
291
292#if !ALIB_SINGLE_THREADED
293RecursiveLock& LI::getLock(LoxImpl* impl)
294{
295 ALIB_DBG( assert::SingleThreaded(); )
296 return impl->Lock;
297}
298#endif
299
300void LI::Acquire(LoxImpl* impl, const lang::CallerInfo& ci ) {
301 #if !ALIB_SINGLE_THREADED
302 ALIB_REL_DBG( impl->Lock.AcquireRecursive();
303 , impl->Lock.AcquireRecursive(ci); )
304 #else
305 ALIB_DBG( assert::SingleThreaded());
306 #endif
307 ++impl->AcquirementsCount;
308 impl->scopeInfo.Set( ci );
309}
310
311void LI::Release(LoxImpl* impl) {
312 impl->scopeInfo.PopNestedScope();
313 --impl->AcquirementsCount;
314 #if !ALIB_SINGLE_THREADED
315 impl->Lock.ReleaseRecursive(ALIB_CALLER_PRUNED);
316 #endif
317}
318
319void LI::init(LoxImpl* impl) {
320 impl->logableContainers.reserve(5); // 5 equals the recursive logging warning threshold
321
322 // create domain trees
323 impl->domains = impl->monoAllocator().New<Domain>(impl->monoAllocator, impl->poolAllocator, "" );
324 impl->internalDomains= impl->monoAllocator().New<Domain>(impl->monoAllocator, impl->poolAllocator, "$" );
325
326 // create internal Subdomains
327 const NString internalDomainList[]= {"LGR","DMN", "PFX", "THR", "LGD", "VAR" };
328 for ( auto& it : internalDomainList )
329 impl->internalDomains->Find( it, 1, nullptr );
330 impl->maxDomainPathLength= Lox::InternalDomains.Length() + 3;
331
332 // read domain substitution rules from configuration
333 Variable var= variables::CampVariable(ALOX);
334 {
336 var.Declare( Variables::DOMAIN_SUBSTITUTION,
337 #if !ALIB_CHARACTERS_WIDE
338 GetName(impl)
339 #else
340 String128( GetName( impl ) )
341 #endif
342 );
343 }
344 if ( var.IsDefined() ) {
345 for( int ruleNo= 0 ; ruleNo < var.Size() ; ++ruleNo ) {
346 Substring rule= var.GetString(ruleNo);
347 if( rule.Trim().IsEmpty() )
348 continue;
349
350 integer idx= rule.IndexOf( A_CHAR("->") );
351 if ( idx > 0 ) {
352 NString256 domainPath ( rule.Substring<NC>( 0, idx ) ); domainPath .Trim();
353 NString256 replacement( rule.Substring<NC>( idx + 2, rule.Length() - idx - 2 ) ); replacement.Trim();
354 SetDomainSubstitutionRule( impl, domainPath, replacement );
355 } else {
356 // using alib warning here as we can't do internal logging in the constructor
357 ALIB_WARNING( "ALOX", "Syntax error in variable \"{}\".", var )
358 } } }
359
360}
361
362void LI::Reset(LoxImpl* impl) {
363 #if ALOX_DBG_LOG
364 if( impl == Log::Get()->impl && Log::DebugLogger != nullptr ) {
366 Log::RemoveDebugLogger( Log::Get() );
368 }
369 #endif
370
371 SetSourcePathTrimRule( impl, nullptr, lang::Inclusion::Include,
372 999999, // code for clearing
373 lang::Case::Ignore, NULL_NSTRING, lang::Reach::Global, Priority::NONE );
374
375 // clear the monotonic allocator and rebuild the impl
376 MonoAllocator* loxMA = &impl->monoAllocator;
377 auto snapshot = impl->beforeLox;
378 NString128 name( impl->scopeInfo.loxName);
379 (*loxMA)().Delete(impl);
380 loxMA->Reset(snapshot);
381 ALIB_DBG( auto* dbgNewAddress= )
382 (*loxMA)().New<LoxImpl>(loxMA, name ); // creates the impl at the same position, therefore, it does not need
383 // to be stored (and passed back)
384 ALIB_ASSERT_ERROR( impl == dbgNewAddress, "ALOX", "Internal error. This must never happen." )
385 impl->beforeLox= snapshot;
386}
387
388void LI::SetFileNameCacheCapacity( LoxImpl* impl, integer numberOfLists, integer entriesPerList )
389{ impl->scopeInfo.SetFileNameCacheCapacity( numberOfLists, entriesPerList ); }
390
391#if ALIB_DEBUG_MEMORY
392MonoAllocator& LI::DbgGetMonoAllocator( LoxImpl* impl ) { return impl->monoAllocator; }
393#endif
394
395void LI::SetSourcePathTrimRule( LoxImpl* impl,
396 const NCString& path,
397 lang::Inclusion includeString ,
398 int trimOffset ,
399 lang::Case sensitivity ,
400 const NString& trimReplacement,
401 lang::Reach reach ,
402 Priority priority )
403{
404 impl->scopeInfo.SetSourcePathTrimRule( path, includeString, trimOffset, sensitivity,
405 trimReplacement, reach, priority );
406}
407
408void LI::SetDomain( LoxImpl* impl , const NString& scopeDomain,
409 Scope scope, threads::Thread* thread ) {
410 if ( !isThreadRelatedScope( impl, scope ) )
411 return;
412 setDomain( impl, scopeDomain, scope, false, thread );
413}
414
415//##################################################################################################
416// Methods
417//##################################################################################################
418Logger* LI::GetLogger(LoxImpl* impl, const NString& loggerName ) {
419 ASSERT_ACQUIRED
420
421 // search logger
422 Logger* logger;
423 if ( (logger= impl->domains ->GetLogger( loggerName ) ) != nullptr ) return logger;
424 if ( (logger= impl->internalDomains->GetLogger( loggerName ) ) != nullptr ) return logger;
425
426 // not found
427 BoxesMA& logables= acquireInternalLogables(impl);
428 logables.Add( "No logger named {!Q} found.", loggerName );
429 logInternal( impl, Verbosity::Warning, "LGR", logables );
430 return nullptr;
431}
432
433//! @cond NO_DOX
434namespace {
435void writeVerbVarRecursive( Domain& domain, int loggerNo, CVVerbosities& verbosities,
436 Verbosity parentVerbosity ) {
437 auto verbosity= domain.GetVerbosity( loggerNo );
438 if( parentVerbosity != verbosity || verbosities.ExportAll )
439 verbosities.Add(String256(domain.FullPath) << '=' << verbosity );
440
441 // loop over all subdomains (recursion)
442 for ( Domain& subDomain : domain.SubDomains )
443 writeVerbVarRecursive( subDomain, loggerNo, verbosities, verbosity );
444}
445} // anonymous namespace
446//! @endcond
447
448void LI::writeVerbositiesOnLoggerRemoval( LoxImpl* impl, Logger* logger ) {
449DOX_MARKER([DOX_VARIABLES_REPLACEMENTS2])
450Variable var= variables::CampVariable(ALOX);
452 // a local array of boxes of size two, to fill variable placeholders
453 Box replacements[2]=
454 {
455 GetName( impl ), // name of this Lox
456 logger->GetName() // name of the Logger
457 };
458
459 // declare the individually named variable
460 var.Declare( Variables::VERBOSITY, replacements );
461}
462DOX_MARKER( [DOX_VARIABLES_REPLACEMENTS2])
463 // we do not care about the writing rights.
464 (void) var.Define();
465 auto& cvVerb= var.Get<CVVerbosities>();
466 cvVerb.Clear();
467
468 // collect verbosities
469 {
470 int loggerNoMainDom= impl->domains ->GetLoggerNo( logger );
471 int loggerNoIntDom= impl->internalDomains->GetLoggerNo( logger );
472
473 if ( loggerNoMainDom >= 0 ) writeVerbVarRecursive( *impl->domains , loggerNoMainDom, cvVerb, Verbosity(-1) );
474 if ( loggerNoIntDom >= 0 ) writeVerbVarRecursive( *impl->internalDomains, loggerNoIntDom , cvVerb, Verbosity(-1) );
475 }
476
477 // internal logging
478 {
479 // get variable name. Needs shared acquisition
480 String256 varName;
482 varName << var; // this is needed because we are logging the name of a variable!
483 }
484 BoxesMA& logables= acquireInternalLogables(impl);
485 logables.Add( "Verbosities for logger {!Q} written to variable {!Q}",
486 logger->GetName(), varName );
487 logInternal( impl, Verbosity::Info, "VAR", logables );
488 }
489
490 // verbose logging of the value written
491 {
492 BoxesMA& logables= acquireInternalLogables(impl);
493 logables.Add(" Value:");
494 for( auto& it : cvVerb )
495 logables.Add( "\n ", it );
496 logInternal( impl, Verbosity::Verbose, "VAR", logables );
497} }
498
499void LI::dumpStateOnLoggerRemoval(LoxImpl* impl) {
500 if( !impl->loggerAddedSinceLastDebugState )
501 return;
502 impl->loggerAddedSinceLastDebugState= false;
503
504 Variable variable= variables::CampVariable(ALOX, Variables::DUMP_STATE_ON_EXIT,
506 GetName( impl )
507 #else
508 String128( GetName( impl ) )
509 #endif
510 );
511 if( !variable.IsDefined() )
512 return;
513 NString64 domain;
514 Verbosity verbosity= Verbosity::Info;
515 Substring tok;
516 bool error= false;
517 StateInfo flags= StateInfo::NONE;
518 Tokenizer tknzr;
519 tknzr.Set(variable, ',', true);
520 while( tknzr.HasNext() ) {
521 tok= tknzr.Next();
522
523 // read log domain and verbosity
524 if( tok.IndexOf( '=' ) > 0 ) {
525 if( tok.ConsumePartOf<lang::Case::Ignore, lang::Whitespaces::Trim>( A_CHAR("verbosity"), 1) ) {
526 if( tok.ConsumeChar<lang::Case::Sensitive, lang::Whitespaces::Trim>( '=' ) )
527 enumrecords::Parse<Verbosity>( tok, verbosity );
528 continue;
529 }
530 if( tok.ConsumePartOf<lang::Case::Ignore, lang::Whitespaces::Trim>( A_CHAR("domain"), 1) ) {
531 if( tok.ConsumeChar<lang::Case::Sensitive, lang::Whitespaces::Trim>( '=' ) )
532 domain= tok.Trim();
533 continue;
534 }
535 error= true;
536 break;
537 }
538
539 // read and add state
540 StateInfo stateInfo;
541 if( !enumrecords::Parse<StateInfo>( tok, stateInfo ) ) {
542 error= true;
543 break;
544 }
545
546 // None clears all, others are added
547 if( stateInfo == StateInfo::NONE )
548 flags= StateInfo::NONE;
549 else
550 flags|= stateInfo;
551 }
552 if( error ) {
553 BoxesMA& logables= acquireInternalLogables(impl);
554 logables.Add( "Unknown argument {!Q} in variable {} = {!Q}.",
555 tok, variable, variable.GetString() );
556 logInternal( impl, Verbosity::Error, "VAR", logables);
557 }
558
559 if ( flags != StateInfo::NONE ) {
560 State( impl, domain, verbosity, A_CHAR("Auto dump state on exit requested: "), flags );
561} }
562
563
564bool LI::RemoveLogger( LoxImpl* impl, Logger* logger ) {
565 ASSERT_ACQUIRED
566
567 int noMainDom= impl->domains ->GetLoggerNo( logger );
568 int noIntDom= impl->internalDomains->GetLoggerNo( logger );
569
570 if( noMainDom >= 0 || noIntDom >= 0 ) {
571 dumpStateOnLoggerRemoval(impl);
572 writeVerbositiesOnLoggerRemoval( impl, logger );
573
574 if( noMainDom >= 0 )
575 impl->domains->RemoveLogger( noMainDom );
576
577 if( noIntDom >= 0 )
578 impl->internalDomains->RemoveLogger( noIntDom );
579
580 logger->AcknowledgeLox( impl, lang::ContainerOp::Remove );
581
582 return true;
583 }
584
585 // not found
586 BoxesMA& logables= acquireInternalLogables(impl);
587 logables.Add( "Logger {!Q} not found. Nothing removed.", logger );
588 logInternal( impl, Verbosity::Warning, "LGR", logables );
589 return false;
590}
591
592Logger* LI::RemoveLogger(LoxImpl* impl, const NString& loggerName ) {
593 ASSERT_ACQUIRED
594
595 int noMainDom= impl->domains ->GetLoggerNo( loggerName );
596 int noIntDom= impl->internalDomains->GetLoggerNo( loggerName );
597
598 if( noMainDom >= 0 || noIntDom >= 0 ) {
599 Logger* logger= impl->domains->GetLogger( noMainDom );
600 if( logger == nullptr ) logger= impl->internalDomains->GetLogger( noIntDom );
601
602 dumpStateOnLoggerRemoval(impl);
603 writeVerbositiesOnLoggerRemoval( impl, logger );
604
605 if( noMainDom >= 0 )
606 impl->domains->RemoveLogger( noMainDom );
607
608 if( noIntDom >= 0 )
609 impl->internalDomains->RemoveLogger( noIntDom );
610
611 logger->AcknowledgeLox( impl, lang::ContainerOp::Remove );
612
613 BoxesMA& logables= acquireInternalLogables(impl);
614 logables.Add( "Logger {!Q} removed.", logger );
615 logInternal( impl, Verbosity::Info, "LGR", logables );
616 return logger;
617 }
618
619 // not found
620 BoxesMA& logables= acquireInternalLogables(impl);
621 logables.Add( "Logger {!Q} not found. Nothing removed.", loggerName );
622 logInternal( impl, Verbosity::Warning, "LGR", logables );
623
624 return nullptr;
625}
626
627void LI::SetVerbosity(LoxImpl* impl, Logger* logger, Verbosity verbosity, const NString& domain, Priority priority )
628{ ASSERT_ACQUIRED
629
630 // check
631 if ( logger == nullptr ) {
632 BoxesMA& logables= acquireInternalLogables(impl);
633 logables.Add( "Given Logger is \"null\". Verbosity not set." );
634 logInternal( impl, Verbosity::Error, "LGR", logables );
635 return;
636 }
637
638 // this might create the (path of) domain(s) and set the \e Logger's verbosities like their
639 // first parent's or as given in configuration
640 Domain* dom= evaluateResultDomain( impl, domain );
641
642 // search logger, insert if not found
643 bool isNewLogger= false;
644 int no= dom->GetLoggerNo( logger );
645 if( no < 0 ) {
646 no= dom->AddLogger( logger );
647
648 // error, logger with same name already exists
649 if( no < 0 ) {
650 logInternal( impl, Verbosity::Error, "LGR", acquireInternalLogables(impl)
651 .Add( "Unable to add logger {!Q}. Logger with same name exists.", logger ) );
652
653
654 logInternal( impl, Verbosity::Verbose, "LGR",
655 acquireInternalLogables(impl).Add(
656 " Request was: SetVerbosity({!Q}, {!Q}, Verbosity::{}, {}). ",
657 logger, dom->FullPath, verbosity, priority ) );
658
659 Logger* existingLogger= dom->GetLogger( logger->GetName() );
660 logInternal( impl, Verbosity::Verbose, "LGR", acquireInternalLogables(impl)
661 .Add( " Existing Logger: {!Q}.", existingLogger ) );
662
663 return;
664 }
665
666 // We have to tell the logger that it got inserted, but only if we have not done this yet,
667 // via the 'other' root domain tree.
668 if ( ( dom->GetRoot() == impl->domains ? impl->internalDomains->GetLoggerNo( logger )
669 : impl->domains->GetLoggerNo( logger )
670 ) < 0 )
671 {
672 logger->AcknowledgeLox( impl, lang::ContainerOp::Insert );
673 }
674
675 // store size of name to support tabular internal log output
676 if ( impl->maxLoggerNameLength < logger->GetName().Length() )
677 impl->maxLoggerNameLength= logger->GetName().Length();
678
679 // for internal log
680 isNewLogger= true;
681
682 // remember that a logger was set after the last removal
683 // (for variable LOXNAME_DUMP_STATE_ON_EXIT)
684 impl->loggerAddedSinceLastDebugState= true;
685 }
686
687 // get verbosities from configuration
688 if( isNewLogger ) {
689 BoxesMA& logables= acquireInternalLogables(impl);
690 logables.Add( "Logger {!Q}.", logger );
691 if( domain.StartsWith(Lox::InternalDomains) )
692 logables.Add(" added for internal log messages.");
693 else
694 logables.Add(" added.");
695 logInternal( impl, Verbosity::Info, "LGR", logables );
696
697 // we have to get all verbosities of already existing domains
698 Box replacements[2]= { GetName( impl ), logger->GetName() };
699 Variable varVerbosities= variables::CampVariable(ALOX, Variables::VERBOSITY, replacements );
700 if( varVerbosities.IsDefined() ) {
701 getAllVerbosities( impl, varVerbosities, logger, *impl->domains );
702 getAllVerbosities( impl, varVerbosities, logger, *impl->internalDomains );
703 } }
704
705 // do
706 dom->SetVerbosity( no, verbosity, priority );
707
708 BoxesMA& logables= acquireInternalLogables(impl);
709
710 logables.Add( "Logger {!Q}: {!Fill}{!Q'}{!Fill}= Verbosity::{}.",
711 logger->GetName(),
712 impl->maxLoggerNameLength - logger->GetName().Length(),
713 dom->FullPath,
714 impl->maxDomainPathLength - dom->FullPath.Length() + 1,
715 boxing::MakePair(verbosity, priority) );
716
717 Verbosity actVerbosity= dom->GetVerbosity( no );
718 if( actVerbosity != verbosity )
719 logables.Add( " Lower priority ({} < {}). Remains {}.",
720 priority, dom->GetPriority(no), actVerbosity );
721
722 logInternal( impl, Verbosity::Info, "LGR", logables );
723}
724
725void LI::SetVerbosity(LoxImpl* impl , const NString& loggerName,
726 Verbosity verbosity, const NString& domain , Priority priority ) {
727 // get logger
728 Logger* logger;
729 {
730 ASSERT_ACQUIRED
731
732 Domain* dom= evaluateResultDomain( impl, domain );
733
734 int no= dom->GetLoggerNo( loggerName );
735 if( no >= 0 )
736 logger= dom->GetLogger( no );
737 else {
738 // we have to check if the logger was added in the 'other' tree
739 Domain* otherTree= dom->GetRoot() == impl->domains ? impl->internalDomains
740 : impl->domains;
741 no= otherTree->GetLoggerNo( loggerName );
742 if ( no < 0 ) {
743 // error
744 BoxesMA& logables= acquireInternalLogables(impl);
745 logables.Add( "Logger not found. Request was: SetVerbosity({!Q}, {!Q}, Verbosity::{}, {}).",
746 loggerName, dom->FullPath, verbosity, priority );
747 logInternal( impl, Verbosity::Warning, "LGR", logables );
748 return;
749 }
750
751 logger= otherTree->GetLogger( no );
752 } }
753 // use the overloaded method
754 SetVerbosity( impl, logger, verbosity, domain, priority );
755}
756
757void LI::setDomain( LoxImpl* impl,
758 const NString& scopeDomain, Scope scope,
759 bool removeNTRSD, threads::Thread* thread ) {
760 //note: the public class interface ensures that \p{removeNTRSD} (named thread related scope domain)
761 // only evaluates true for thread related scopes
762
763 ASSERT_ACQUIRED
764
765 // check
766 int pathLevel= checkScopeInformation( impl, scope, "DMN" );
767 if( pathLevel < 0 )
768 return;
769
770 #if !ALIB_SINGLE_THREADED
771 ThreadID threadID= thread != nullptr ? thread->GetID() : UNDEFINED_THREAD;
772 #else
773 threads::ThreadID threadID= UNDEFINED_THREAD;
774 (void) thread;
775 #endif
776
777 NString previousScopeDomain;
778
779 impl->scopeDomains.InitAccess( scope, pathLevel, threadID );
780 if ( removeNTRSD ) {
781 previousScopeDomain= impl->scopeDomains.Remove( scopeDomain );
782 } else {
783 if ( scopeDomain.IsNotEmpty() ) {
784 NString128 trimmable( scopeDomain );
785 previousScopeDomain= impl->scopeDomains.Store( NString(impl->poolAllocator, trimmable.Trim() ) );
786 }
787 else
788 previousScopeDomain= impl->scopeDomains.Remove( nullptr );
789 }
790
791 // log info on this
792 BoxesMA& logables= acquireInternalLogables(impl);
793 if ( !removeNTRSD && scopeDomain.IsNotEmpty() ) {
794 logables.Add("{!Q'} set as default for {}.", scopeDomain, (scope + pathLevel) );
795
796 if ( previousScopeDomain.IsNull() )
797 logInternal( impl, Verbosity::Info, "DMN", logables );
798 else {
799 if ( previousScopeDomain.Equals<NC>( scopeDomain ) ) {
800 logables.Add( "(Wasalreadyset.)");
801 logInternal( impl,Verbosity::Verbose,"DMN",logables);
802 } else {
803 logables.Add( " Replacing previous default {!Q'}.", previousScopeDomain );
804 logInternal( impl, Verbosity::Warning, "DMN", logables );
805 } }
806
807 } else {
808 if ( previousScopeDomain.IsNotNull() ) {
809 logables.Add("{!Q'} removed from {}.", previousScopeDomain, (scope + pathLevel) );
810 logInternal( impl, Verbosity::Info, "DMN", logables );
811 } else {
812 if ( removeNTRSD )
813 logables.Add("{!Q'} not found. Nothing removed for {}.", scopeDomain );
814 else
815 logables.Add("Empty Scope Domain given, nothing registered for {}.", scopeDomain);
816
817 logables.Add( scope + pathLevel);
818 logInternal( impl, Verbosity::Warning, "DMN", logables );
819 } }
820
821 // it is on us to delete the previous one
822 if ( previousScopeDomain.IsNotNull() )
823 previousScopeDomain.Free(impl->poolAllocator);
824}
825
826void LI::RemoveThreadDomain( LoxImpl* impl, const NString& scopeDomain,
827 Scope scope, threads::Thread* thread ) {
828 if ( !isThreadRelatedScope( impl, scope ) )
829 return;
830
831 // check
832 if ( scopeDomain.IsEmpty() ) {
833 BoxesMA& logables= acquireInternalLogables(impl);
834 logables.Add( "Illegal parameter. No scope domain path given. Nothing removed for {}.",
835 scope );
836 logInternal( impl, Verbosity::Warning, "DMN", logables );
837
838 // do nothing
839 return;
840 }
841
842 // invoke internal master
843 setDomain( impl, scopeDomain, scope, true, thread);
844}
845
846void LI::SetDomainSubstitutionRule(LoxImpl* impl, const NString& domainPath,
847 const NString& replacement ) {
848 // check null param: clears all rules
849 if ( domainPath.IsEmpty() ) {
850 impl->oneTimeWarningCircularDS= false;
851 impl->domainSubstitutions.Clear();
852 logInternal( impl, Verbosity::Info, "DMN", "Domain substitution rules removed.");
853 return;
854 }
855
856
857 // create rule
858 DomainSubstitutionRule newRule( domainPath, replacement );
859 if ( newRule.Search.IsEmpty() ) {
860 logInternal( impl, Verbosity::Warning, "DMN", "Illegal domain substitution rule. Nothing stored." );
861 return;
862 }
863
864 // search existing rule
865 ListMA<DomainSubstitutionRule>::iterator it;
866 for( it= impl->domainSubstitutions.begin(); it != impl->domainSubstitutions.end() ; ++it ) {
867 if ( (*it).type == newRule.type
868 && (*it).Search.Equals<NC>( newRule.Search ) )
869 break;
870 }
871
872 // no replacement given?
873 if ( replacement.IsEmpty() ) {
874 BoxesMA& logables= acquireInternalLogables(impl);
875 if ( it == impl->domainSubstitutions.end() ) {
876 logables.Add("Domain substitution rule {!Q} not found. Nothing to remove.", domainPath );
877 logInternal( impl, Verbosity::Warning, "DMN", logables );
878 return;
879 }
880
881 logables.Add("Domain substitution rule {!Q} -> {!Q} removed.", domainPath, (*it).Replacement );
882 logInternal( impl, Verbosity::Info, "DMN", logables );
883 (void) impl->domainSubstitutions.erase( it );
884 return;
885 }
886
887 BoxesMA& logables= acquireInternalLogables(impl);
888 logables.Add("Domain substitution rule {!Q} -> {!Q} set.", domainPath, newRule.Replacement );
889
890 // change of rule
891 NString256 msg;
892 if ( it != impl->domainSubstitutions.end() ) {
893 msg << " Replacing previous -> \"" << (*it).Replacement << "\".";
894 logables.Add( msg );
895 (*it).Replacement.Reset( newRule.Replacement );
896 }
897 else
898 impl->domainSubstitutions.emplace_back( newRule );
899
900 if( ALOX.IsBootstrapped() ) // this function might be called very early.
901 logInternal( impl, Verbosity::Info, "DMN", logables );
902}
903
904void LI::setPrefix(LoxImpl* impl, const Box& prefix, Scope scope, threads::Thread* thread ) {
905 ASSERT_ACQUIRED
906
907 // check
908 int pathLevel= checkScopeInformation( impl, scope, "PFX" );
909 if( pathLevel < 0 )
910 return;
911
912 #if !ALIB_SINGLE_THREADED
913 ThreadID threadID= thread != nullptr ? thread->GetID() : UNDEFINED_THREAD;
914 #else
915 threads::ThreadID threadID= UNDEFINED_THREAD;
916 (void) thread;
917 #endif
918
919 impl->scopePrefixes.InitAccess( scope, pathLevel, threadID );
920 bool isVoidOrEmpty= prefix.IsType<void>()
921 || prefix.IsNull()
922 || ( prefix.IsArray() && !prefix.UnboxLength() );
923
924 Box* previousLogable= !isVoidOrEmpty ? impl->scopePrefixes.Store( impl->newPO<PrefixLogable>( impl->poolAllocator, prefix ) )
925 : impl->scopePrefixes.Remove( nullptr );
926
927
928 BoxesMA& logables= acquireInternalLogables(impl);
929 logables.Add( "Object ");
930 Verbosity intMsgVerbosity= Verbosity::Info;
931 if ( !isVoidOrEmpty ) {
932 logables.Add( prefix, " added as prefix logable for {}.", (scope + pathLevel) );
933
934 if ( previousLogable != nullptr ) {
935 if ( previousLogable->Call<FEquals>( prefix ) ) {
936 logables.Add(" (Same as before.)");
937 intMsgVerbosity= Verbosity::Verbose;
938 }
939 else
940 logables.Add(" Replacing previous {}.", *previousLogable );
941 }
942 } else {
943 if ( previousLogable != nullptr )
944 logables.Add( "{!Q} removed from list of prefix logables for {}.", *previousLogable);
945 else {
946 logables.Add( "<nullptr> given but no prefix logable to remove for {}.");
947 intMsgVerbosity= Verbosity::Warning;
948 }
949 logables.Add( scope + pathLevel );
950 }
951
952 logInternal( impl, intMsgVerbosity, "PFX", logables );
953
954 // it is on us to delete the previous one
955 if ( previousLogable != nullptr )
956 impl->deletePO(static_cast<PrefixLogable*>( previousLogable ));
957}
958
959
960void LI::SetPrefix( LoxImpl* impl , const Box& prefix,
961 const NString& domain, lang::Inclusion otherPLs ) {
962
963 ASSERT_ACQUIRED
964
965 Domain* dom= evaluateResultDomain( impl, domain );
966
967 bool isVoidOrEmpty= prefix.IsType<void>()
968 || prefix.IsNull()
969 || ( prefix.IsArray() && !prefix.UnboxLength() );
970
971 BoxesMA& logables= acquireInternalLogables(impl);
972 Verbosity intLogVerbosity= Verbosity::Info;
973 PrefixLogable* removedLogable= nullptr;
974
975 if ( !isVoidOrEmpty ) {
976 // create logable: if String* type, then copy the string. We are responsible, then.
977 logables.Add( "Object {} added as prefix logable for ", prefix );
978
979 dom->PrefixLogables.emplace_back( impl->newPO<PrefixLogable>( impl->poolAllocator, prefix ), otherPLs );
980 } else {
981 auto cntPLs= dom->PrefixLogables.size();
982 if ( cntPLs > 0 ) {
983 removedLogable= dom->PrefixLogables.back().first;
984 dom->PrefixLogables.pop_back();
985 logables.Add( "Object {} removed from list of prefix logables for",
986 *static_cast<Box*>(removedLogable) );
987 } else {
988 logables.Add( "No prefix logables to remove for" );
989 intLogVerbosity= Verbosity::Warning;
990 } }
991
992 logables.Add(" domain {!Q'}.", dom->FullPath);
993 logInternal( impl, intLogVerbosity, "PFX", logables );
994
995 if( removedLogable )
996 impl->deletePO(removedLogable);
997}
998
999
1000#if defined (__GLIBCXX__) || defined(_LIBCPP_VERSION) || defined(__APPLE__) || defined(__ANDROID_NDK__)
1001void LI::SetStartTime(LoxImpl* impl, time_t startTime, const NString& loggerName )
1002{
1003 TickConverter converter;
1004 SetStartTime( impl, converter.ToTicks( DateTime::FromEpochSeconds( startTime ) ), loggerName );
1005}
1006
1007#elif defined( _WIN32 )
1008 void LI::SetStartTime(LoxImpl* impl, const FILETIME& startTime, const NString& loggerName )
1009 {
1010 TickConverter converter;
1011 SetStartTime( impl, converter.ToTicks( DateTime::FromFileTime( startTime ) ), loggerName );
1012 }
1013#else
1014 #pragma message "Unknown Platform in file: " __FILE__ )
1015#endif
1016
1017void LI::SetStartTime(LoxImpl* impl, Ticks startTime, const NString& loggerName ) {
1018 ASSERT_ACQUIRED
1019
1020 bool foundOne= false;
1021 for( int loggerNo= 0; loggerNo < impl->domains->CountLoggers(); ++loggerNo ) {
1022 // request logger only from main domain tree
1023 Logger* logger= impl->domains->GetLogger( loggerNo );
1024 if( loggerName.IsNotEmpty() && !loggerName.Equals<NC, lang::Case::Ignore>( logger->GetName()) )
1025 continue;
1026 foundOne= true;
1027
1028 // log info on this
1029 BoxesMA& logables= acquireInternalLogables(impl);
1030 logables.Add( "Logger {!Q}: Start time set to ", logger->GetName() );
1031 if ( !startTime.IsSet() ) {
1032 startTime= Ticks::Now();
1033 logables.Add( "'now'" );
1034 } else {
1035 DateTime asDateTime;
1036 TextLogger* asTextLogger= dynamic_cast<TextLogger*>(logger);
1037 if( asTextLogger != nullptr )
1038 asDateTime= asTextLogger->DateConverter.ToDateTime( startTime );
1039 else
1040 asDateTime= TickConverter().ToDateTime( startTime );
1041 logables.Add( "{:yyyy-MM-dd HH:mm:ss}", asDateTime );
1042 }
1043 // do
1044 logger->TimeOfCreation.SetAs( startTime );
1045 logger->TimeOfLastLog .SetAs( startTime );
1046
1047 logInternal( impl, Verbosity::Info, "LGR", logables );
1048 }
1049
1050 if ( loggerName.IsNotEmpty() && !foundOne ) {
1051 BoxesMA& logables= acquireInternalLogables(impl);
1052 logables.Add( "Logger {!Q}: not found. Start time not set.", loggerName );
1053 logInternal( impl, Verbosity::Error, "LGR", logables );
1054 return;
1055} }
1056
1057
1058void LI::MapThreadName(LoxImpl* impl, const String& threadName, threads::ThreadID id ) {
1059 #if !ALIB_SINGLE_THREADED
1060
1061 ASSERT_ACQUIRED
1062
1063 // get current thread id
1064 String origThreadName;
1065 if ( id == 0 ) {
1066 Thread* t= Thread::GetCurrent();
1067 id= t->GetID();
1068 origThreadName= t->GetName();
1069 }
1070 else
1071 origThreadName= nullptr;
1072
1073 // add entry
1074 impl->scopeInfo.threadDictionary.EmplaceOrAssign(id, threadName);
1075
1076 // log info on this
1077 BoxesMA& logables= acquireInternalLogables(impl);
1078 logables.Add( "Mapped thread ID {} to {!Q}.", id, threadName);
1079 if ( origThreadName.IsNotEmpty() )
1080 logables.Add(" Original thread name: {!Q}.", origThreadName );
1081 logInternal( impl, Verbosity::Info, "THR", logables );
1082 #else
1083 (void) impl;
1084 (void) threadName;
1085 (void) id;
1086 #endif
1087}
1088
1089void LI::once( LoxImpl* impl,
1090 const NString& domain, Verbosity verbosity,
1091 const Box& logable,
1092 const String& pGroup,
1093 Scope scope,
1094 int quantity ) {
1095 int pathLevel= checkScopeInformation( impl, scope, "DMN" );
1096 if( pathLevel < 0 )
1097 return;
1098
1099 // We need a group. If none is given, there are two options:
1100 NString512 group(pGroup);
1101 bool groupWasEmtpy= group.IsEmpty();
1102 if ( groupWasEmtpy ) {
1103 // GLOBAL scope: exact code line match
1104 if ( scope == Scope::Global ) {
1105 scope= Scope::Filename;
1106 group._('#')._( impl->scopeInfo.GetLineNumber() );
1107 }
1108
1109 // not GLOBAL scope: Unique group per Scope
1110 else
1111 group._( impl->noKeyHashKey );
1112 }
1113
1114 // get the store
1115 impl->scopeLogOnce.InitAccess( scope, pathLevel, UNDEFINED_THREAD );
1116
1117 SSMap<int>* map= impl->scopeLogOnce.Get();
1118 if( map == nullptr ) {
1119 map= impl->newPO<SSMap<int>>(impl->poolAllocator);
1120 impl->scopeLogOnce.Store( map );
1121 }
1122
1123 // create map entry (if not created yet)
1124 auto it= map->Find( group );
1125 if (it == map->end() )
1126 it= map->InsertUnique( std::make_pair( NString(impl->poolAllocator, group), 0) );
1127
1128 // log Once
1129 if ( quantity >= 0 ) {
1130 if ( it->second < quantity ) {
1131 ++it->second;
1132
1133 // do the log
1134 GetLogableContainer(impl) .Add( std::forward<const Box&>( logable ) );
1135 Entry( impl, domain, verbosity );
1136
1137 // log info if this was the last time
1138 if( it->second == quantity ) {
1139 BoxesMA& logables= acquireInternalLogables(impl);
1140 logables.Add( "Once() reached limit of {} logs. No further logs for ", quantity );
1141
1142 if ( groupWasEmtpy )
1143 logables.Add( scope == Scope::Global ? Box( "this line" )
1144 : Box(scope + pathLevel) );
1145 else {
1146 logables.Add( "group {!Q}", group );
1147 if ( scope != Scope::Global )
1148 logables.Add(" in ", (scope + pathLevel) );
1149 }
1150 logables.Add('.');
1151
1152 logInternal( impl, Verbosity::Info, "", logables );
1153 } } }
1154
1155 // log Nth
1156 else {
1157 if ( it->second++ % -quantity == 0 ) {
1158 GetLogableContainer(impl) .Add( std::forward<const Box&>( logable ) );
1159 Entry( impl, domain, verbosity );
1160} } }
1161
1162void LI::store( LoxImpl* impl, const Box& data, const NString& pKey, Scope scope ) {
1163 // We need a key. If none is given, we use a constant one indicating that storage is
1164 // associated exclusively with scope
1165 NString256 key(pKey);
1166 bool keyWasEmtpy= key.IsEmpty();
1167 if ( keyWasEmtpy )
1168 key= impl->noKeyHashKey;
1169
1170 // get path level
1171 int pathLevel= 0;
1172 if ( scope > Scope::Path ) {
1173 pathLevel= int( scope - Scope::Path );
1174 scope= Scope::Path;
1175 }
1176
1177 // get the store
1178 impl->scopeLogData.InitAccess( scope, pathLevel, UNDEFINED_THREAD );
1179 SSMap<Box>* map= impl->scopeLogData.Get();
1180 if( map == nullptr ) {
1181 map= impl->newPO<SSMap<Box>>(impl->poolAllocator);
1182 impl->scopeLogData.Store( map );
1183 }
1184
1185 BoxesMA& logables= acquireInternalLogables(impl);
1186
1187 // create map entry (if not created yet)
1188 auto it= map->Find( key );
1189 if ( !data.IsType<void>() ) {
1190 bool replacedPrevious= false;
1191 if ( it == map->end() )
1192 map->InsertUnique( std::make_pair( NString(impl->poolAllocator, key), data ) );
1193 else {
1194 replacedPrevious= true;
1195 it->second= data;
1196 }
1197
1198 // log info if this was the last time
1199 logables.Add( "Stored data " );
1200
1201 if ( !keyWasEmtpy )
1202 logables.Add( " with key {!Q} ", key );
1203 logables.Add( "in {}.", (scope + pathLevel) );
1204 if ( replacedPrevious )
1205 logables.Add( " (Replaced and deleted previous.)" );
1206 }
1207
1208 // delete
1209 else {
1210 if ( it != map->end() ) {
1211 auto keyString= it->first;
1212 map->erase( it );
1213 if ( map->Size() == 0 ) {
1214 impl->deletePO(map);
1215 impl->scopeLogData.Remove( nullptr );
1216 }
1217 keyString.Free(impl->poolAllocator);
1218 logables.Add( "Deleted map data " );
1219 }
1220 else
1221 logables.Add( "No map data found to delete " );
1222
1223 if ( !keyWasEmtpy )
1224 logables.Add( " with key {!Q} ", key );
1225 logables.Add( "in {}.", (scope + pathLevel) );
1226 }
1227
1228 LI::logInternal( impl, Verbosity::Info, "LGD", logables );
1229}
1230
1231
1232Box LI::retrieve( LoxImpl* impl, const NString& pKey, Scope scope ) {
1233 // We need a key. If none is given, we use a constant one indicating that storage is
1234 // associated exclusively with scope
1235 NString256 key= pKey;
1236 bool keyWasEmtpy= key.IsEmpty();
1237 if ( keyWasEmtpy )
1238 key= impl->noKeyHashKey;
1239
1240 int pathLevel= 0;
1241 if ( scope > Scope::Path ) {
1242 pathLevel= int( scope - Scope::Path );
1243 scope= Scope::Path;
1244 }
1245
1246 // get the data (create if not found)
1247 impl->scopeLogData.InitAccess( scope, pathLevel, UNDEFINED_THREAD );
1248 Box returnValue;
1249 SSMap<Box>* map= impl->scopeLogData.Get();
1250 if( map != nullptr ) {
1251 auto it= map->Find( key );
1252 if ( it != map->end() )
1253 returnValue= it->second;
1254 }
1255
1256 if ( returnValue.IsType<void>() )
1257 store( impl, Box(), pKey, scope + pathLevel );
1258
1259 // log info if this was the last time
1260 BoxesMA& logables= acquireInternalLogables(impl);
1261 logables.Add( "Data " );
1262
1263 if ( !keyWasEmtpy )
1264 logables.Add( " with key {!Q} ", key );
1265 logables.Add( "in ", (scope + pathLevel), ( !returnValue.IsType<void>() ? " received."
1266 : " not found." ) );
1267
1268 logInternal( impl, Verbosity::Info, "LGD", logables );
1269 return returnValue;
1270}
1271
1272
1273void LI::State( LoxImpl* impl,
1274 const NString& domain,
1275 Verbosity verbosity,
1276 const String& headLine,
1277 StateInfo flags ) {
1278 ASSERT_ACQUIRED
1279
1280 NAString buf;
1281 buf.SetBuffer( 2048 );
1282 if ( headLine.IsNotEmpty() )
1283 buf._<NC>( headLine ).NewLine();
1284
1285 GetState( impl, buf, flags );
1286
1287 GetLogableContainer(impl) .Add( buf );
1288 Entry( impl, domain, verbosity );
1289}
1290
1291BoxesMA& LI::GetLogableContainer(LoxImpl* impl) {
1292 auto cntAcquirements= impl->CountAcquirements();
1293 ALIB_ASSERT_ERROR( cntAcquirements >= 1, "ALOX", "Lox not acquired." )
1294 ALIB_ASSERT_WARNING( cntAcquirements < 5, "ALOX", "Logging recursion depth >= 5" )
1295 while( int(impl->logableContainers.size()) < cntAcquirements )
1296 impl->logableContainers.emplace_back( impl->monoAllocator().New<BoxesMA>(impl->monoAllocator) );
1297 BoxesMA& logables= *impl->logableContainers[size_t(cntAcquirements - 1)];
1298 logables.clear();
1299 return logables;
1300}
1301
1302void LI::Entry(LoxImpl* impl, const NString& domain, Verbosity verbosity ) {
1303 ASSERT_ACQUIRED
1304
1305 // auto-initialization of debug loggers
1306 #if ALOX_DBG_LOG
1307 if( impl == Log::Get()->impl
1308 && impl->domains->CountLoggers() == 0
1309 && Log::DebugLogger == nullptr )
1310 Log::AddDebugLogger( Log::Get() );
1311 #endif
1312
1313 ALIB_ASSERT_ERROR(ALOX.IsBootstrapped(), "ALOX", "ALox (ALib) was not properly bootstrapped." )
1314
1315 ++impl->CntLogCalls;
1316
1317 if ( impl->domains->CountLoggers() == 0 )
1318 return;
1319
1320 log( impl,
1321 evaluateResultDomain( impl, domain ),
1322 verbosity,
1323 *impl->logableContainers[size_t(impl->CountAcquirements() - 1)],
1324 lang::Inclusion::Include );
1325}
1326
1327int LI::IsActive(LoxImpl* impl, Verbosity verbosity, const NString& domain, NAString* resultDomain){
1328 ASSERT_ACQUIRED
1329
1330 // auto-initialization of debug loggers
1331 #if ALOX_DBG_LOG
1332 if( impl == Log::Get()->impl
1333 && impl->domains->CountLoggers() == 0
1334 && Log::DebugLogger == nullptr )
1335 Log::AddDebugLogger( Log::Get() );
1336 #endif
1337
1338 ALIB_ASSERT_ERROR(ALOX.IsBootstrapped(), "ALOX", "ALox (ALib) was not properly bootstrapped." )
1339
1340 if ( impl->domains->CountLoggers() == 0 )
1341 return 0;
1342
1343 Domain* dom= evaluateResultDomain( impl, domain );
1344 if ( resultDomain != nullptr )
1345 resultDomain->_( dom->FullPath );
1346
1347 int result= 0;
1348 for ( int i= 0; i < dom->CountLoggers() ; ++i )
1349 if( dom->IsActive( i, verbosity ) )
1350 ++result;
1351 return result;
1352}
1353
1354void LI::IncreaseLogCounter( LoxImpl* impl) { ++impl->CntLogCalls; }
1355
1356void LI::entryDetectDomainImpl(LoxImpl* impl, Verbosity verbosity ) {
1357 BoxesMA& logables= *impl->logableContainers[size_t(impl->CountAcquirements() - 1)];
1358 if ( logables.Size() > 1 && logables[0].IsArrayOf<nchar>() ) {
1359 NString firstArg= logables[0].Unbox<NString>();
1360
1361 // accept internal domain at the start
1362 integer idx= 0;
1363 if( firstArg.StartsWith( Lox::InternalDomains ) )
1364 idx+= Lox::InternalDomains.Length();
1365
1366 // loop over domain and check for illegal characters
1367 bool illegalCharacterFound= false;
1368 for( ; idx< firstArg.Length() ; ++idx ) {
1369 char c= firstArg[idx];
1370 if (! ( isdigit( c )
1371 || ( c >= 'A' && c <= 'Z' )
1372 || c == '-'
1373 || c == '_'
1374 || c == '/'
1375 || c == '.'
1376 ) )
1377 {
1378 illegalCharacterFound= true;
1379 break;
1380 } }
1381
1382 if ( illegalCharacterFound ) {
1383 Entry( impl, nullptr, verbosity );
1384 return;
1385 }
1386
1387 logables.erase( logables.begin() );
1388 Entry( impl, firstArg, verbosity );
1389 return;
1390 }
1391
1392 Entry( impl, nullptr, verbosity );
1393}
1394
1395
1396//##################################################################################################
1397// internals
1398//##################################################################################################
1399Domain* LI::evaluateResultDomain(LoxImpl* impl, const NString& domainPath ) {
1400 NString128 resDomain;
1401
1402 // 0. internal domain tree?
1403 if ( domainPath.StartsWith( Lox::InternalDomains ) ) {
1404 // cut "$/" from the path
1405 resDomain._( domainPath, Lox::InternalDomains.Length() );
1406 return findDomain( impl, *impl->internalDomains, resDomain );
1407 }
1408
1409 // loop over scopes
1410 NString64 localPath; localPath.DbgDisableBufferReplacementWarning();
1411 impl->scopeDomains.InitWalk( Scope::ThreadInner,
1412 // we have to provide NULL_STRING if parameter is empty
1413 domainPath.IsNotEmpty() ? localPath._(domainPath)
1414 : NULL_NSTRING
1415 );
1416 NString nextDefault;
1417 while( (nextDefault= impl->scopeDomains.Walk() ).IsNotNull() ) {
1418 ALIB_ASSERT( nextDefault.IsNotEmpty(), "ALOX" )
1419
1420 if ( resDomain.IsNotEmpty() )
1421 resDomain.InsertAt( "/", 0);
1422 resDomain.InsertAt( nextDefault, 0 );
1423
1424 // absolute path? That's it
1425 if ( resDomain.CharAtStart() == Domain::Separator() )
1426 break;
1427 }
1428 return findDomain( impl, *impl->domains, resDomain );
1429}
1430
1431void LI::getVerbosityFromConfig(LoxImpl* impl, Variable& v, Logger* logger, Domain& dom ) {
1432 // get logger number. It may happen that the logger is not existent in this domain tree.
1433 int loggerNo= dom.GetLoggerNo( logger ) ;
1434 if ( loggerNo < 0 )
1435 return;
1436
1437 auto& cvVerb = v.Get<alib::lox::CVVerbosities>();
1438
1439 for (auto it : cvVerb) {
1440 Tokenizer verbosityTknzr( it, '=' );
1441
1442 NString256 domainStrBuf;
1443 Substring domainStrParser= verbosityTknzr.Next();
1444 if ( domainStrParser.ConsumeString<lang::Case::Ignore>( A_CHAR("INTERNAL_DOMAINS")) ) {
1445 while ( domainStrParser.ConsumeChar('/') )
1446 ;
1447 domainStrBuf << Lox::InternalDomains << domainStrParser;
1448 }
1449 else
1450 domainStrBuf._( domainStrParser );
1451
1452 NSubstring domainStr= domainStrBuf ;
1453
1454 Substring verbosityStr= verbosityTknzr.Next();
1455 if ( verbosityStr.IsEmpty() )
1456 continue;
1457
1458 int searchMode= 0;
1459 if ( domainStr.ConsumeChar ( '*' ) ) searchMode+= 2;
1460 if ( domainStr.ConsumeCharFromEnd( '*' ) ) searchMode+= 1;
1461 if( ( searchMode == 0 && dom.FullPath.Equals <NC ,lang::Case::Ignore>( domainStr ) )
1462 || ( searchMode == 1 && dom.FullPath.StartsWith<CHK,lang::Case::Ignore>( domainStr ) )
1463 || ( searchMode == 2 && dom.FullPath.EndsWith <CHK,lang::Case::Ignore>( domainStr ) )
1464 || ( searchMode == 3 && dom.FullPath.IndexOf <CHK,lang::Case::Ignore>( domainStr ) >=0 )
1465 )
1466 {
1467 Verbosity verbosity(Verbosity::Info);
1468 enumrecords::Parse<Verbosity>(verbosityStr, verbosity );
1469 dom.SetVerbosity( loggerNo, verbosity, v.GetPriority() );
1470
1471 // log info on this
1472 NString512 msg;
1473 msg._<NC>( "Logger \"" )._<NC>( logger->GetName() ) ._<NC>( "\":" )._(NTab(11 + impl->maxLoggerNameLength))
1474 ._<NC>( '\'' )._<NC>( dom.FullPath )
1475 ._( '\'' ).InsertChars(' ', impl->maxDomainPathLength - dom.FullPath.Length() + 1 )
1476 ._( "= Verbosity::" )
1477 ._( boxing::MakePair(verbosity, dom.GetPriority( loggerNo )) ).TrimEnd()
1478 ._<NC>( '.' );
1479
1480 logInternal( impl, Verbosity::Info, "LGR", msg );
1481} } }
1482
1483void LI::getDomainPrefixFromConfig(LoxImpl* impl, Domain& dom ) {
1484 Variable variable= variables::CampVariable(ALOX);
1486 const Declaration* decl= Declaration::Get( Variables::PREFIXES);
1487 decl= ALOX.GetConfig()->StoreDeclaration( decl,
1488 #if !ALIB_CHARACTERS_WIDE
1489 GetName( impl )
1490 #else
1491 String128( GetName( impl ) )
1492 #endif
1493 );
1494 if( !variable.Try(decl) )
1495 return;
1496 }
1497
1498 Tokenizer prefixTokOuter;
1499 prefixTokOuter.Set(variable, ';', true);
1500 while(prefixTokOuter.HasNext()) {
1501 Tokenizer prefixTok( prefixTokOuter.Next(), '=' );
1502
1503 NString128 domainStrBuf;
1504 Substring domainStrParser= prefixTok.Next();
1505 if ( domainStrParser.ConsumeString<lang::Case::Ignore>( A_CHAR("INTERNAL_DOMAINS")) ) {
1506 while ( domainStrParser.ConsumeChar('/') )
1507 ;
1508 domainStrBuf << Lox::InternalDomains << domainStrParser;
1509 }
1510 else
1511 domainStrBuf._( domainStrParser );
1512
1513 NSubstring domainStr= domainStrBuf ;
1514
1515 Tokenizer prefixTokInner( prefixTok.Next(), ',' );
1516 Substring prefixStr= prefixTokInner.Next();
1517 if ( prefixStr.IsEmpty() )
1518 continue;
1519 if ( prefixStr.ConsumeChar( '\"' ) )
1520 prefixStr.ConsumeCharFromEnd( '\"' );
1521
1522 lang::Inclusion otherPLs= lang::Inclusion::Include;
1523 prefixTokInner.Next();
1524 if ( prefixTokInner.Actual.IsNotEmpty() )
1525 enumrecords::ParseEnumOrTypeBool( prefixTokInner.Actual, otherPLs, lang::Inclusion::Exclude, lang::Inclusion::Include );
1526
1527 int searchMode= 0;
1528 if ( domainStr.ConsumeChar ( '*' ) ) searchMode+= 2;
1529 if ( domainStr.ConsumeCharFromEnd( '*' ) ) searchMode+= 1;
1530 if( ( searchMode == 0 && dom.FullPath.Equals <NC ,lang::Case::Ignore>( domainStr ) )
1531 || ( searchMode == 1 && dom.FullPath.StartsWith<CHK,lang::Case::Ignore>( domainStr ) )
1532 || ( searchMode == 2 && dom.FullPath.EndsWith <CHK,lang::Case::Ignore>( domainStr ) )
1533 || ( searchMode == 3 && dom.FullPath.IndexOf <CHK,lang::Case::Ignore>( domainStr ) >=0 )
1534 )
1535 {
1536 dom.PrefixLogables.emplace_back( impl->newPO<PrefixLogable>( impl->poolAllocator, prefixStr ), otherPLs );
1537
1538 // log info on this
1539 NString128 msg; msg._<NC>( "String \"" )._<NC>( prefixStr )._<NC>( "\" added as prefix logable for domain \'" )
1540 ._<NC>( dom.FullPath )
1541 ._<NC>( "\'. (Retrieved from configuration variable \'" )._<NC>(variable)._( "\'.)" );
1542
1543 logInternal( impl, Verbosity::Info, "PFX", msg );
1544} } }
1545
1546void LI::getAllVerbosities(LoxImpl* impl, Variable& varVerbosities, Logger* logger, Domain& dom) {
1547 // get verbosity for us
1548 getVerbosityFromConfig( impl, varVerbosities, logger, dom );
1549
1550 // loop over all subdomains (recursion)
1551 for ( Domain& subDomain : dom.SubDomains )
1552 getAllVerbosities( impl, varVerbosities, logger, subDomain );
1553}
1554
1555
1556Domain* LI::findDomain(LoxImpl* impl, Domain& rootDomain, NString domainPath ) {
1557 int maxSubstitutions= 10;
1558 NString128 substPath;
1559 for(;;) {
1560 // loop for creating domains, one by one
1561 Domain* dom= nullptr;
1562 for(;;) {
1563 bool wasCreated;
1564 dom= rootDomain.Find( domainPath, 1, &wasCreated );
1565 if ( wasCreated ) {
1566 // get maximum domain path length (for nicer State output only...)
1567 if ( impl->maxDomainPathLength < dom->FullPath.Length() )
1568 impl->maxDomainPathLength= dom->FullPath.Length();
1569
1570 // log info on new domain
1571 BoxesMA& logables= acquireInternalLogables(impl);
1572 logables.Add( "{!Q} registered.", dom->FullPath );
1573 logInternal( impl, Verbosity::Info, "DMN", logables );
1574 }
1575
1576 // read domain from config
1577 if ( !dom->ConfigurationAlreadyRead )
1578 { dom->ConfigurationAlreadyRead= true;
1579
1580 Box replacements[2];
1581 for ( int i= 0; i < dom->CountLoggers(); ++i ) {
1582 Logger* logger= dom->GetLogger(i);
1583 replacements[0]= GetName( impl );
1584 replacements[1]= logger->GetName();
1585 Variable varVerbosities= variables::CampVariable(ALOX, Variables::VERBOSITY, replacements );
1586 if ( varVerbosities.IsDefined() )
1587 getVerbosityFromConfig( impl, varVerbosities, logger, *dom );
1588 }
1589
1590 getDomainPrefixFromConfig( impl, *dom );
1591 }
1592
1593 if ( wasCreated ) {
1594 if ( dom->CountLoggers() == 0 )
1595 logInternal( impl, Verbosity::Verbose, "DMN", " No loggers set, yet." );
1596 else
1597 for ( int i= 0; i < dom->CountLoggers(); ++i ) {
1598 NString256 msg; msg._(" \"")._( dom->GetLogger(i)->GetName() )._("\": ");
1599 msg.InsertChars( ' ', impl->maxLoggerNameLength + 6 - msg.Length() );
1600 msg._( dom->FullPath )._(" = " )
1601 ._(boxing::MakePair(dom->GetVerbosity(i), dom->GetPriority(i)));
1602 logInternal( impl, Verbosity::Verbose, "DMN", msg );
1603 } }
1604 else
1605 break;
1606 }
1607
1608 // apply domain substitutions
1609 if( !impl->domainSubstitutions.empty() ) {
1610 substPath.Reset();
1611 NSubstring domFullPath= dom->FullPath;
1612 if ( domFullPath.CharAtStart<NC>() == '$' )
1613 domFullPath.ConsumeChar();
1614
1615 while( maxSubstitutions-- > 0 ) {
1616 // loop over rules
1617 bool substituted= false;
1618 for( auto& rule : impl->domainSubstitutions ) {
1619 switch( rule.type ) {
1620 case DomainSubstitutionRule::Type::StartsWith:
1621 if( substPath.IsEmpty() ) {
1622 if ( domFullPath.StartsWith( rule.Search ) ) {
1623 substPath._( rule.Replacement )._( domFullPath, rule.Search.Length() );
1624 substituted= true;
1625 continue;
1626 }
1627 } else {
1628 if ( substPath.StartsWith( rule.Search ) ) {
1629 substPath.ReplaceSubstring<NC>( rule.Replacement, 0, rule.Search.Length() );
1630 substituted= true;
1631 continue;
1632 } }
1633 break;
1634
1635 case DomainSubstitutionRule::Type::EndsWith:
1636 if( substPath.IsEmpty() ) {
1637 if ( domFullPath.EndsWith( rule.Search ) ) {
1638 substPath._( domFullPath, 0, domFullPath.Length() - rule.Search.Length() )._( rule.Replacement );
1639 substituted= true;
1640 continue;
1641 }
1642 } else {
1643 if ( substPath.EndsWith( rule.Search ) ) {
1644 substPath.DeleteEnd( rule.Search.Length() )._( rule.Replacement );
1645 substituted= true;
1646 continue;
1647 } }
1648 break;
1649
1650
1651 case DomainSubstitutionRule::Type::Substring:
1652 {
1653 if( substPath.IsEmpty() ) {
1654 integer idx= domFullPath.IndexOf( rule.Search );
1655 if ( idx >= 0 ) {
1656 substPath._( domFullPath, 0, idx )._( rule.Replacement)._( domFullPath, idx + rule.Search.Length() );
1657 substituted= true;
1658 continue; //next rule
1659 }
1660 } else {
1661 integer idx= substPath.IndexOf( rule.Search, 0 );
1662 if ( idx >= 0 ) {
1663 substPath.ReplaceSubstring<NC>( rule.Replacement, idx, rule.Search.Length() );
1664 substituted= true;
1665 continue; //next rule
1666 } } }
1667 break;
1668
1669
1670 case DomainSubstitutionRule::Type::Exact:
1671 {
1672 if( substPath.IsEmpty() ) {
1673 if ( domFullPath.Equals<NC>( rule.Search ) ) {
1674 substPath._( rule.Replacement);
1675 substituted= true;
1676 continue; //next rule
1677 }
1678 if ( domFullPath.CharAtStart<NC>() == '$' ) {
1679 substPath._( rule.Replacement);
1680 substituted= true;
1681 continue; //next rule
1682 }
1683 } else {
1684 if ( substPath.Equals<NC>( rule.Search) ) {
1685 substPath.Reset( rule.Replacement );
1686 substituted= true;
1687 continue; //next rule
1688 } } }
1689 break;
1690
1691 default: ALIB_ERROR("ALOX", "Illegal switch state." ) break;
1692 } // switch rule type
1693
1694 }//rules loop
1695
1696 // stop if non was found
1697 if( !substituted )
1698 break;
1699 }
1700
1701 // too many substitutions?
1702 if ( maxSubstitutions <= 0 && !impl->oneTimeWarningCircularDS ) {
1703 impl->oneTimeWarningCircularDS= true;
1704 logInternal( impl, Verbosity::Error, "DMN",
1705 "The Limit of 10 domain substitutions was reached. Circular substitution assumed!"
1706 " (This error is only reported once!)" );
1707 }
1708
1709 // anything substituted?
1710 if( substPath.Length() > 0 ) {
1711 domainPath= substPath;
1712 continue;
1713 } }
1714
1715 return dom;
1716} }
1717
1718int LI::checkScopeInformation(LoxImpl* impl, Scope& scope, const NString& internalDomain ) {
1719 int pathLevel= 0;
1720 if ( scope > Scope::Path ) {
1721 pathLevel= int( scope - Scope::Path );
1722 scope= Scope::Path;
1723 }
1724
1725 if ( ( scope == Scope::Path && impl->scopeInfo.GetFullPath().IsEmpty() )
1726 || ( scope == Scope::Filename && impl->scopeInfo.GetFileName().IsEmpty() )
1727 || ( scope == Scope::Method && impl->scopeInfo.GetMethod() .IsEmpty() ) )
1728 {
1729 BoxesMA& logables= acquireInternalLogables(impl);
1730 logables.Add( "Missing scope information. Cant use {}.", (scope + pathLevel) );
1731 logInternal( impl, Verbosity::Error, internalDomain, logables );
1732 return -1;
1733 }
1734 return pathLevel;
1735}
1736
1737bool LI::isThreadRelatedScope(LoxImpl* impl, Scope scope ) {
1738 // check
1739 if ( scope == Scope::ThreadOuter
1740 || scope == Scope::ThreadInner )
1741 return true;
1742
1743 BoxesMA& logables= acquireInternalLogables(impl);
1744 logables.Add( "Illegal parameter, only Scope::ThreadOuter and Scope::ThreadInner allowed."
1745 " Given: {}.", scope );
1746 logInternal( impl, Verbosity::Error, "DMN", logables );
1747
1748 #if ALIB_DEBUG
1749 alib::assert::Raise( { impl->scopeInfo.GetOrigFile(),
1750 impl->scopeInfo.GetLineNumber(),
1751 impl->scopeInfo.GetMethod(),
1752 #if !ALIB_SINGLE_THREADED
1753 impl->scopeInfo.GetThreadNativeID(),
1754 #elif ALIB_EXT_LIB_THREADS_AVAILABLE
1755 std::thread::id(),
1756 #endif
1757 impl->scopeInfo.GetTypeInfo()
1758 },
1759 0, "Illegal scope type \"{}\" given. Only Scope::ThreadOuter and "
1760 "Scope::ThreadInner allowed.", scope );
1761 #endif
1762
1763 return false;
1764}
1765
1766void LI::log( LoxImpl* impl , Domain* dom,
1767 Verbosity verbosity, BoxesMA& logables, lang::Inclusion includePrefixes ) {
1768 ++dom->CntLogCalls;
1769 bool logablesCollected= false;
1770 PrefixLogable marker(impl->poolAllocator, nullptr);
1771 for ( int i= 0; i < dom->CountLoggers() ; ++i )
1772 if( dom->IsActive( i, verbosity ) ) {
1773 // lazily collect objects once an active logger is found
1774 if ( !logablesCollected ) {
1775 logablesCollected= true;
1776 impl->scopePrefixes.InitWalk( Scope::ThreadInner, &marker );
1777 const Box* next;
1778 int userLogablesSize= int( logables.Size() );
1779 int threadInnersSize= -1;
1780
1781 while( (next= impl->scopePrefixes.Walk() ) != nullptr ) {
1782 if( next != &marker ) {
1783 // this is false for internal domains (only domain specific logables are added there)
1784 if ( includePrefixes == lang::Inclusion::Include ) {
1785 // after marker is read, logables need to be prepended. This is checked below
1786 // using "qtyThreadInners < 0"
1787 if ( next->IsType<BoxesMA*>() ) {
1788 auto* boxes= next->Unbox<BoxesMA*>();
1789 for (auto pfxI= boxes->Size() - 1 ; pfxI >= 0 ; --pfxI )
1790 logables.emplace( logables.begin() + ( threadInnersSize < 0 ? userLogablesSize : 0 ),
1791 (*boxes)[size_t(pfxI)] );
1792 }
1793 else if ( next->IsType<Boxes*>() ) {
1794 auto* boxes= next->Unbox<Boxes*>();
1795 for (auto pfxI= boxes->Size() - 1 ; pfxI >= 0 ; --pfxI )
1796 logables.emplace( logables.begin() + ( threadInnersSize < 0 ? userLogablesSize : 0 ),
1797 (*boxes)[size_t(pfxI)] );
1798 }
1799 else if ( next->IsType<BoxesPA*>() ) {
1800 auto* boxes= next->Unbox<BoxesPA*>();
1801 for (auto pfxI= boxes->Size() - 1 ; pfxI >= 0 ; --pfxI )
1802 logables.emplace( logables.begin() + ( threadInnersSize < 0 ? userLogablesSize : 0 ),
1803 (*boxes)[size_t(pfxI)] );
1804 }
1805 else
1806 logables.emplace( logables.begin() + ( threadInnersSize < 0 ? userLogablesSize : 0 ), *next );
1807 } }
1808
1809 // was this the actual? then insert domain-associated logables now
1810 else {
1811 bool excludeOthers= false;
1812 threadInnersSize= int( logables.Size() ) - userLogablesSize;
1813 Domain* pflDom= dom;
1814 while ( pflDom != nullptr ) {
1815 for( auto it= pflDom->PrefixLogables.rbegin() ; it != pflDom->PrefixLogables.rend() ; ++it ) {
1816 // a list of logables? Copy them
1817 PrefixLogable& prefix= *it->first;
1818 if ( prefix.IsType<Boxes*>() ) {
1819 auto* boxes= prefix.Unbox<Boxes*>();
1820 for (auto pfxI= boxes->Size() - 1 ; pfxI >= 0 ; --pfxI )
1821 logables.emplace( logables.begin(),
1822 (*boxes)[size_t(pfxI)] );
1823 }
1824 else if ( prefix.IsType<BoxesMA*>() ) {
1825 auto* boxes= prefix.Unbox<BoxesMA*>();
1826 for (auto pfxI= boxes->Size() - 1 ; pfxI >= 0 ; --pfxI )
1827 logables.emplace( logables.begin(),
1828 (*boxes)[size_t(pfxI)] );
1829 }
1830 else if ( prefix.IsType<BoxesPA*>() ) {
1831 auto* boxes= prefix.Unbox<BoxesPA*>();
1832 for (auto pfxI= boxes->Size() - 1 ; pfxI >= 0 ; --pfxI )
1833 logables.emplace( logables.begin(),
1834 (*boxes)[size_t(pfxI)] );
1835 }
1836 else
1837 logables.emplace( logables.begin(), prefix );
1838
1839
1840 if ( it->second == lang::Inclusion::Exclude ) {
1841 excludeOthers= true;
1842 break;
1843 } }
1844
1845 pflDom= excludeOthers ? nullptr : pflDom->Parent;
1846 }
1847
1848 // found a stoppable one? remove those from thread inner and break
1849 if (excludeOthers) {
1850 for ( int ii= 0; ii < threadInnersSize ; ++ii )
1851 logables.pop_back();
1852 break;
1853 } } }
1854 } // end of collection
1855
1856 Logger* logger= dom->GetLogger(i);
1857 { ALIB_LOCK_RECURSIVE_WITH(*logger)
1858 ++logger->CntLogs;
1859 logger->Log( *dom, verbosity, logables, impl->scopeInfo );
1860 logger->TimeOfLastLog= Ticks::Now();
1861} } }
1862
1863BoxesMA& LI::acquireInternalLogables(LoxImpl* impl) {
1864 if( integer(impl->internalLogables.size()) == impl->internalLogRecursionCounter ) {
1865 BoxesMA* newLogables= impl->monoAllocator().New<BoxesMA>(impl->monoAllocator);
1866 impl->internalLogables.emplace_back( newLogables );
1867 }
1868
1869 return *impl->internalLogables[size_t(impl->internalLogRecursionCounter++)];
1870}
1871
1872void LI::logInternal(LoxImpl* impl, Verbosity verbosity, const NString& subDomain, BoxesMA& msg ) {
1873 ALIB_ASSERT_ERROR(ALOX.IsBootstrapped(), "ALOX", "ALox (ALib) was not properly bootstrapped." )
1874 log( impl, findDomain( impl, *impl->internalDomains, subDomain ), verbosity, msg, lang::Inclusion::Exclude );
1875
1876 impl->internalLogables[size_t(--impl->internalLogRecursionCounter)]->clear();
1877}
1878
1879void LI::logInternal( LoxImpl* impl , Verbosity verbosity,
1880 const NString& subDomain, const NString& msg ) {
1881 BoxesMA& logables= acquireInternalLogables(impl);
1882 logables.Add( msg );
1883 logInternal( impl, verbosity, subDomain, logables );
1884}
1885
1886#if !DOXYGEN
1887
1888namespace {
1889void getStateDomainRecursive( Domain& domain, integer maxDomainPathLength, NAString& buf );
1890void getStateDomainRecursive( Domain& domain, integer maxDomainPathLength, NAString& buf ) {
1891 integer reference= buf.Length();
1892 buf._(" "); domain.ToString( buf );
1893 integer idx= buf.IndexOf( '[', reference );
1894 buf.InsertChars( ' ', maxDomainPathLength + 5 - idx + reference, idx);
1895 buf.NewLine();
1896
1897 // loop over all subdomains (recursion)
1898 for ( Domain& subDomain : domain.SubDomains )
1899 getStateDomainRecursive( subDomain, maxDomainPathLength, buf );
1900}
1901
1902void getStateDomainsWithDiffVerb( Domain& dom, int loggerNo, std::vector<Domain*>& results );
1903void getStateDomainsWithDiffVerb( Domain& dom, int loggerNo, std::vector<Domain*>& results ) {
1904 if ( dom.Parent == nullptr
1905 || dom.Parent->GetVerbosity(loggerNo) != dom.GetVerbosity(loggerNo) )
1906 results.emplace_back( &dom );
1907
1908 for( auto& it : dom.SubDomains )
1909 getStateDomainsWithDiffVerb( it, loggerNo, results );
1910}
1911
1912void getStateCollectPrefixes( Domain& dom, integer indentSpaces, NAString& target );
1913void getStateCollectPrefixes( Domain& dom, integer indentSpaces, NAString& target ) {
1914 AString buffer;
1915 for ( auto& pfl : dom.PrefixLogables ) {
1916 buffer.InsertChars( ' ', indentSpaces );
1917 buffer << '"';
1918 integer actLen= buffer.Length();
1919 buffer._( *static_cast<Box*>(pfl.first) );
1920 ESC::ReplaceToReadable( buffer, actLen );
1921 buffer << Escape( lang::Switch::On, actLen );
1922 buffer << '"';
1923 if ( pfl.second == lang::Inclusion::Exclude )
1924 buffer._<NC>( " (Excl.)" );
1925 buffer._<NC>( Tab( 25, -1 ) );
1926 buffer._<NC>( "<domain> [" )._<NC>( dom.FullPath )._<NC>(']').NewLine();
1927 }
1928 target << buffer;
1929
1930 for( auto& subDom : dom.SubDomains )
1931 getStateCollectPrefixes( subDom, indentSpaces, target );
1932}
1933
1934} // anonymous namespace
1935
1936#endif // !DOXYGEN
1937
1938
1939void LI::GetState( LoxImpl* impl, NAString& buf, StateInfo flags ) {
1940 ASSERT_ACQUIRED
1941
1942 ScopeDump scopeDump( IF_ALIB_THREADS( impl->scopeInfo.threadDictionary, )
1943 impl->noKeyHashKey, buf );
1944
1945 if ( HasBits( flags, StateInfo::CompilationFlags ) ) {
1946 buf._<NC>( "ALib Version: " )._<NC>( alib::VERSION)
1947 ._<NC>(" (Rev. ") ._ ( alib::REVISION)._(')').NewLine();
1948 buf._<NC>( "ALib Compiler Symbols:" ).NewLine();
1949 {
1950 for( auto& p : alib::COMPILATION_FLAG_MEANINGS ) {
1951 buf << " " << NField( p.Name, 41, lang::Alignment::Left ) << ':'
1952 << (alib::COMPILATION_FLAGS.bits[p.Flag/8] & (1 << p.Flag % 8) ? " On" : " Off")
1953 << NEW_LINE;
1954 }
1955
1956 }
1957
1958 buf.NewLine();
1959 }
1960
1961 // basic lox info
1962 if( alib::HasBits( flags, StateInfo::Basic ) )
1963 buf._<NC>( "Name: \"" )._( impl->scopeInfo.GetLoxName() )._('\"').NewLine();
1964
1965 if( HasBits( flags, StateInfo::Version ) ) {
1966 buf._<NC>( "Version: " )._<NC>( alib::VERSION)
1967 ._<NC>(" (Rev. " )._( alib::REVISION)._(')').NewLine();
1968 }
1969
1970 if( HasBits( flags, StateInfo::Basic ) )
1971 buf._<NC>( "#Log Calls: " )._<NC>( impl->CntLogCalls ).NewLine();
1972
1973 if( HasBits( flags, StateInfo::Basic )
1974 || HasBits( flags, StateInfo::Version ) )
1975 buf.NewLine();
1976
1977 // source path trim info
1978 if( HasBits( flags, StateInfo::SPTR ) ) {
1979 buf._<NC>( "Source Path Trimming Rules: " ).NewLine();
1980
1981 int cnt= 0;
1982 // do 2 times, 0== global list, 1 == local list
1983 for( int trimInfoNo= 0; trimInfoNo < 2 ; ++trimInfoNo ) {
1984 // choose local or global list
1985 std::vector<ScopeInfo::SourcePathTrimRule>* trimInfoList=
1986 trimInfoNo == 0 ? &ScopeInfo::GlobalSPTRs
1987 : &impl->scopeInfo.LocalSPTRs;
1988
1989
1990 // loop over trimInfo
1991 for ( auto& ti : *trimInfoList ) {
1992 ++cnt;
1993 buf._<NC>( trimInfoNo == 0 ? " Global: "
1994 : " Local: " );
1995 buf._<NC>( ti.IsPrefix ? "\"" : "\"*");
1996 buf._<NC>( ti.Path )._<NC>( "\", " );
1997 buf._<NC>( ti.IncludeString );
1998 if ( ti.TrimOffset != 0 )
1999 buf._<NC>( ti.Path )._<NC>( "\", Offset: " )._<NC>( ti.TrimOffset );
2000 buf._<NC>( ", Priority: " )._( ti.Priority );
2001 buf.NewLine();
2002 } }
2003
2004
2005 if ( cnt == 0 )
2006 buf._<NC>(" <no rules set>" ).NewLine();
2007 buf.NewLine();
2008 }
2009
2010 // domain substitutions
2011 if( HasBits( flags, StateInfo::DSR ) ) {
2012 buf._<NC>( "Domain Substitution Rules: " ).NewLine();
2013 if( !impl->domainSubstitutions.empty() ) {
2014 // get size
2015 integer maxWidth= 0;
2016 for ( auto& it : impl->domainSubstitutions )
2017 if ( maxWidth < it.Search.Length() )
2018 maxWidth = it.Search.Length();
2019 maxWidth+= 2;
2020
2021 // write
2022 for ( auto& it : impl->domainSubstitutions ) {
2023 buf._<NC>( " " );
2024 if ( it.type == DomainSubstitutionRule::Type::EndsWith
2025 || it.type == DomainSubstitutionRule::Type::Substring )
2026 buf._<NC>( '*' );
2027
2028 buf._<NC>( it.Search );
2029 if ( it.type == DomainSubstitutionRule::Type::StartsWith
2030 || it.type == DomainSubstitutionRule::Type::Substring )
2031 buf._<NC>( '*' );
2032
2033 buf._<NC>( NTab( maxWidth, -1, 0 ) )
2034 ._<NC>( " -> " )
2035 ._<NC>( it.Replacement );
2036 buf.NewLine();
2037 } }
2038 else
2039 buf._<NC>(" <no rules set>" ).NewLine();
2040 buf.NewLine();
2041 }
2042
2043 // Log Once Counters
2044 if( HasBits( flags, StateInfo::Once ) ) {
2045 buf._<NC>( "Once() Counters: " ).NewLine();
2046 if ( scopeDump.writeStoreMap( &impl->scopeLogOnce ) == 0 )
2047 buf._<NC>(" <no Once() counters set>" ).NewLine();
2048 buf.NewLine();
2049 }
2050
2051 // Log Data
2052 if( HasBits( flags, StateInfo::LogData ) ) {
2053 buf._<NC>( "Log Data: " ).NewLine();
2054 if ( scopeDump.writeStoreMap( &impl->scopeLogData ) == 0 )
2055 buf._<NC>(" <no data objects stored>" ).NewLine();
2056 buf.NewLine();
2057 }
2058
2059 // Prefix Logables
2060 if( HasBits( flags, StateInfo::PrefixLogables ) ) {
2061 buf._<NC>( "Prefix Logables: " ).NewLine();
2062 integer oldLength= buf.Length();
2063 scopeDump.writeStore( &impl->scopePrefixes, 2 );
2064 getStateCollectPrefixes( *impl->domains, 2, buf );
2065 if ( oldLength == buf.Length() )
2066 buf._<NC>(" <no prefix logables set>" ).NewLine();
2067 buf.NewLine();
2068 }
2069
2070 // thread mappings
2071 if( HasBits( flags, StateInfo::ThreadMappings ) ) {
2072 #if !ALIB_SINGLE_THREADED
2073 buf._<NC>( "Named Threads: " ).NewLine();
2074 if ( impl->scopeInfo.threadDictionary.Size() == 0 )
2075 buf._<NC>(" <no thread name mappings set>" ).NewLine();
2076 else
2077 for ( auto& pair : impl->scopeInfo.threadDictionary ) {
2078 buf._<NC>( " " ) << NField( String32() << '(' << pair.first << "):", 7, lang::Alignment::Left )
2079 << '\"' << pair.second << '\"';
2080 buf.NewLine();
2081 }
2082 buf.NewLine();
2083 #endif
2084 }
2085
2086 // Scope Domains
2087 if( HasBits( flags, StateInfo::ScopeDomains ) ) {
2088 buf._<NC>( "Scope Domains: " ).NewLine();
2089 if ( scopeDump.writeStore( &impl->scopeDomains, 2 ) == 0 )
2090 buf._<NC>(" <no scope domains set>" ).NewLine();
2091 buf.NewLine();
2092 }
2093
2094 // Loggers
2095 if( HasBits( flags, StateInfo::Loggers ) ) {
2096 TickConverter dateTimeConverter;
2097 std::vector<Domain*> domainsWithDiffVerb;
2098 for (int treeNo= 0; treeNo < 2; ++treeNo ) {
2099 int cnt= 0;
2100 Domain* domTree;
2101 if( treeNo==0 ) {
2102 domTree= impl->domains;
2103 buf._<NC>( "Loggers:" ).NewLine();
2104 } else {
2105 domTree= impl->internalDomains;
2106 buf._<NC>( "Loggers on Internal Domains:" ).NewLine();
2107 }
2108
2109 for ( int loggerNo= 0; loggerNo< domTree->CountLoggers(); ++loggerNo ) {
2110 ++cnt;
2111 String64 as64;
2112 CalendarDateTime ct(lang::Initialization::Suppress);
2113
2114 Logger* logger= domTree->GetLogger(loggerNo);
2115 buf._<NC>( " " )._<NC>( *logger ).NewLine();
2116 buf._<NC>( " Lines logged: " )._<NC>( logger->CntLogs ).NewLine();
2117
2118 ct.Set( dateTimeConverter.ToDateTime(logger->TimeOfCreation) );
2119 buf._<NC>( " Creation time: " )._<NC>( ct.Format( A_CHAR("yyyy-MM-dd HH:mm:ss"), as64.Reset()) ).NewLine();
2120
2121 ct.Set( dateTimeConverter.ToDateTime(logger->TimeOfLastLog) );
2122 buf._<NC>( " Last log time: " )._<NC>( ct.Format( A_CHAR("yyyy-MM-dd HH:mm:ss"), as64.Reset()) ).NewLine();
2123
2124 domainsWithDiffVerb.clear();
2125 getStateDomainsWithDiffVerb( *domTree, loggerNo, domainsWithDiffVerb);
2126 for ( Domain* dom : domainsWithDiffVerb ) {
2127 buf._<NC>(" ")
2128 ._( dom == *domainsWithDiffVerb.begin() ? "Verbosities: "
2129 : " " );
2130
2131 integer tabRef= buf.Length();
2132 buf << dom->FullPath << NTab( impl->maxDomainPathLength +1, tabRef);
2133
2134 buf << "= " << boxing::MakePair(dom->GetVerbosity( loggerNo ), dom->GetPriority(loggerNo) )
2135 << NEW_LINE;
2136 } }
2137 if ( cnt == 0 )
2138 buf._<NC>(" <no loggers attached>" ).NewLine();
2139 buf.NewLine();
2140 } }
2141
2142 // Internal Domains
2143 if( HasBits( flags, StateInfo::InternalDomains ) ) {
2144 buf._<NC>( "Internal Domains:" ).NewLine();
2145 getStateDomainRecursive( *impl->internalDomains, impl->maxDomainPathLength, buf );
2146 buf.NewLine();
2147 }
2148
2149 // Domains
2150 if( HasBits( flags, StateInfo::Domains ) ) {
2151 buf._<NC>( "Domains:" ).NewLine();
2152 getStateDomainRecursive( *impl->domains , impl->maxDomainPathLength, buf );
2153 buf.NewLine();
2154} }
2155
2156} // namespace alib::lox[::detail]
2157
2158
2159
2160}} // namespace [alib::lox]
2161# include "ALib.Lang.CIMethods.H"
2162
2163#undef UNDEFINED_THREAD
2164#undef ASSERT_ACQUIRED
SharedConfiguration & GetConfig()
Definition camp.inl:211
bool IsBootstrapped()
Definition camp.inl:183
ALIB_DLL void SetBuffer(integer newCapacity)
bool ConsumeCharFromEnd(TChar consumable)
void Set(const TString< TChar > &src, TChar delimiter, bool skipEmptyTokens=false)
DbgLockAsserter Dbg
The debug tool instance.
Definition lock.inl:65
DateTime ToDateTime(Ticks ticks)
#define LOG_RELEASE
#define LOG_ACQUIRE
#define ALIB_BOXING_VTABLE_DEFINE(TMapped, Identifier)
#define ALIB_LOCK_SHARED_WITH(lock)
Definition alib.inl:1341
#define IF_ALIB_THREADS(...)
Definition alib.inl:401
#define A_CHAR(STR)
#define ALIB_ASSERT(cond, domain)
Definition alib.inl:1065
#define ALIB_WARNING(domain,...)
Definition alib.inl:1063
#define ALIB_ASSERT_WARNING(cond, domain,...)
Definition alib.inl:1067
#define ALIB_ERROR(domain,...)
Definition alib.inl:1062
#define ALIB_LOCK_RECURSIVE_WITH(lock)
Definition alib.inl:1340
#define ALIB_DBG(...)
Definition alib.inl:853
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
#define ALIB_CALLER_PRUNED
Definition alib.inl:1024
#define ALIB_COMMA
Definition alib.inl:963
#define ALIB_LOCK_WITH(lock)
Definition alib.inl:1339
#define ALIB_REL_DBG(releaseCode,...)
Definition alib.inl:855
#define ALIB_CHARACTERS_WIDE
Definition alib.inl:888
void Raise(const lang::CallerInfo &ci, int type, std::string_view domain, TArgs &&... args)
Definition assert.inl:181
const TChar * Search(const TChar *haystack, integer haystackLength, TChar needle)
integer Length(const TChar *cstring)
Definition functions.inl:89
std::conditional_t< ArrayTraits< T, nchar >::Access !=Policy::NONE, nchar, std::conditional_t< ArrayTraits< T, wchar >::Access !=Policy::NONE, wchar, std::conditional_t< ArrayTraits< T, xchar >::Access !=Policy::NONE, xchar, void > > > Type
constexpr bool HasBits(TEnum element, TEnum selection) noexcept
Definition bitwise.inl:325
@ Add
Arithmetic addition ('+'). Precedence 800.
platform_specific integer
Definition integers.inl:32
integer ThreadID
The ALib thread identifier type.
Definition thread.inl:23
strings::TEscape< character > Escape
Type alias in namespace alib.
Definition format.inl:532
threads::Lock Lock
Type alias in namespace alib.
Definition lock.inl:124
NLocalString< 128 > NString128
Type alias name for TLocalString<nchar,128>.
CompilationFlagMeaningsEntry COMPILATION_FLAG_MEANINGS[40]
NLocalString< 64 > NString64
Type alias name for TLocalString<nchar,64>.
strings::TTab< character > Tab
Type alias in namespace alib.
Definition format.inl:512
LocalString< 256 > String256
Type alias name for TLocalString<character,256>.
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
unsigned char REVISION
strings::util::TTokenizer< character > Tokenizer
Type alias in namespace alib.
variables::Variable Variable
Type alias in namespace alib.
LocalString< 128 > String128
Type alias name for TLocalString<character,128>.
time::DateTime DateTime
Type alias in namespace alib.
Definition datetime.inl:185
LocalString< 64 > String64
Type alias name for TLocalString<character,64>.
constexpr CString NEW_LINE
A zero-terminated string containing the new-line character sequence.
Definition cstring.inl:616
strings::TSubstring< nchar > NSubstring
Type alias in namespace alib.
boxing::TBoxes< lang::HeapAllocator > Boxes
Type alias in namespace alib.
Definition boxes.inl:189
monomem::TPoolAllocator< MonoAllocator > PoolAllocator
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2198
strings::TAString< nchar, lang::HeapAllocator > NAString
Type alias in namespace alib.
boxing::TBoxes< PoolAllocator > BoxesPA
Type alias in namespace alib.
Definition boxes.inl:196
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
threads::Thread Thread
Type alias in namespace alib.
Definition thread.inl:387
strings::TTab< nchar > NTab
Type alias in namespace alib.
Definition format.inl:515
int VERSION
strings::TCString< nchar > NCString
Type alias in namespace alib.
Definition cstring.inl:484
strings::util::CalendarDateTime CalendarDateTime
Type alias in namespace alib.
Definition calendar.inl:512
LocalString< 32 > String32
Type alias name for TLocalString<character,32>.
lox::ALoxCamp ALOX
The singleton instance of ALib Camp class ALoxCamp.
Definition aloxcamp.cpp:53
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1149
threads::RecursiveLock RecursiveLock
Type alias in namespace alib.
boxing::TBoxes< MonoAllocator > BoxesMA
Type alias in namespace alib.
Definition boxes.inl:193
strings::TField< nchar > NField
Type alias in namespace alib.
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2189
NLocalString< 512 > NString512
Type alias name for TLocalString<nchar,512>.
NLocalString< 256 > NString256
Type alias name for TLocalString<nchar,256>.
TCompilationFlags COMPILATION_FLAGS
NLocalString< 32 > NString32
Type alias name for TLocalString<nchar,32>.
time::TickConverter TickConverter
Type alias in namespace alib.
strings::TSubstring< character > Substring
Type alias in namespace alib.
lox::detail::Logger Logger
Type alias in namespace alib.
Definition logger.inl:156
lox::textlogger::TextLogger TextLogger
Type alias in namespace alib.
unsigned char bits[5]
The Flags.
Definition lang.mpp:67