11# define HPP_ALIB_LOX_PROPPERINCLUDE
14# undef HPP_ALIB_LOX_PROPPERINCLUDE
37 Formatters.emplace_back( firstLevelFormatter );
44 "ALox object converter recursion counter > 0.\n"
45 "Note: This error indicates, that a previous format operation (log statement) contained\n"
46 " corrupt format values, which caused the formatter to behave undefined, including\n"
47 " the corruption of the execution stack of ALox logging." )
58 // get a formatter. We use a clone per recursion depth!
59 // So, did we have this depth already before? If not, create a new set of formatters formatter
60 if( size_t( cntRecursion ) >= Formatters.size() )
62 // create a pair of recursion formatters
63 Formatter* recursionFormatter= new FormatterPythonStyle();
64 recursionFormatter->Next.InsertDerived<FormatterJavaStyle>();
65 recursionFormatter->CloneSettings( *Formatters[0] );
66 Formatters.emplace_back( recursionFormatter );
69 Formatter* formatter= Formatters[size_t( cntRecursion )];
73 formatter->FormatArgs( target, logables );
77 target << ALOX.GetResource("TLFmtExc
");
78 ALIB_LOCK_RECURSIVE_WITH( lang::format::Formatter::DefaultLock )
85void StandardConverter::SetAutoSizes( AutoSizes* autoSizes )
87 FormatterPythonStyle* fmtPS= dynamic_cast<FormatterPythonStyle*>( Formatters[0] );
88 if (fmtPS != nullptr )
89 fmtPS->Sizes= autoSizes;
92AutoSizes* StandardConverter::GetAutoSizes()
94 FormatterPythonStyle* fmtPS= dynamic_cast<FormatterPythonStyle*>( Formatters[0] );
95 if (fmtPS != nullptr )
100void StandardConverter::ResetAutoSizes()
102 FormatterPythonStyle* fmtPS;
103 for( auto* elem : Formatters )
104 if ( (fmtPS= dynamic_cast<FormatterPythonStyle*>( elem )) != nullptr )
105 fmtPS->Sizes->Reset();
108// #################################################################################################
110// #################################################################################################
111void TextLogger::writeMetaInfo( AString& buf, detail::Domain& domain, Verbosity verbosity,
112 detail::ScopeInfo& scope )
115 auto& fmt= varFormatMetaInfo.Get<FormatMetaInfo>();
116 if ( fmt.Format.IsEmpty() )
119 // clear DateTime singleton
120 callerDateTime.Year= (std::numeric_limits<int>::min)();
122 Substring format( fmt.Format );
125 // get next and log substring between commands
126 integer idx= format.IndexOf( '%' );
129 format.ConsumeChars<NC, lang::CurrentData::Keep>( idx, buf, 1 );
130 processVariable( domain.FullPath, verbosity, scope, buf, format );
140void TextLogger::processVariable( const NString& domainPath,
142 detail::ScopeInfo& scope,
144 Substring& variable )
148 auto& fmt= varFormatMetaInfo .Get<FormatMetaInfo>();
149 auto& autoSizes= varFormatAutoSizes.Get<FormatAutoSizes>();
151 switch ( variable.ConsumeChar() )
158 switch( c2= variable.ConsumeChar() )
160 case 'P': // SP: full path
162 val= scope.GetFullPath();
164 val= GetFormatOther().NoSourceFileInfo;
167 case 'p': // Sp: trimmed path
169 integer previousLength= dest.Length();
170 scope.GetTrimmedPath( dest );
171 if( dest.Length() != previousLength )
173 val= GetFormatOther().NoSourceFileInfo;
176 case 'F': // file name
178 val= scope.GetFileName();
180 val= GetFormatOther().NoSourceFileInfo;
183 case 'f': // file name without extension
185 val= scope.GetFileNameWithoutExtension();
187 val= GetFormatOther().NoSourceFileInfo;
191 case 'M': // method name
193 val= scope.GetMethod();
195 val= GetFormatOther().NoMethodInfo;
198 case 'L': // line number
200 dest._<NC>( scope.GetLineNumber() );
206 ALIB_ASSERT_WARNING( FormatWarningOnce, "ALOX",
207 "Unknown format variable
'%S{}' (only one warning)
", c2 )
208 ALIB_DBG( FormatWarningOnce= true; )
219 c2= variable.ConsumeChar();
224 // get time stamp as CalendarDateTime once
225 if ( callerDateTime.Year == (std::numeric_limits<int>::min)() )
226 callerDateTime.Set( DateConverter.ToDateTime( scope.GetTimeStamp() ) );
228 // if standard format, just write it out
229 if ( GetFormatDate().Date.Equals<NC>( A_CHAR("yyyy-MM-dd
") ) )
231 dest._<NC>( alib::Format( callerDateTime.Year, 4 ) )._<NC>( '-' )
232 ._<NC>( alib::Format( callerDateTime.Month, 2 ) )._<NC>( '-' )
233 ._<NC>( alib::Format( callerDateTime.Day, 2 ) );
235 // user-defined format
237 callerDateTime.Format( GetFormatDate().Date, dest );
246 // get time stamp as CalendarDateTime once
247 if ( callerDateTime.Year == (std::numeric_limits<int>::min)() )
248 callerDateTime.Set( DateConverter.ToDateTime( scope.GetTimeStamp() ) );
250 // avoid the allocation of a) a StringBuilder (yes, a string builder is allocated inside StringBuilder.AppendFormat!)
251 // and b) a DateTime object, if the format is the unchanged standard. And it is faster anyhow.
252 if ( GetFormatDate().TimeOfDay.Equals<NC>( A_CHAR("HH:mm:ss
") ) )
254 dest._<NC>( alib::Format(callerDateTime.Hour, 2) )._<NC>( ':' )
255 ._<NC>( alib::Format(callerDateTime.Minute, 2) )._<NC>( ':' )
256 ._<NC>( alib::Format(callerDateTime.Second, 2) );
259 // user-defined format
261 callerDateTime.Format( GetFormatDate().TimeOfDay, dest );
264 // %TC: Time elapsed since created
265 else if ( c2 == 'C' )
267 auto elapsedTime= scope.GetTimeStamp() - TimeOfCreation;
268 auto elapsedSecs= elapsedTime.InAbsoluteSeconds();
269 CalendarDuration elapsed( elapsedTime );
271 // determine number of segments to write and match this to recent (autosizes) value
272 int timeSize= elapsedSecs >= 24*3600 ? 6
273 : elapsedSecs >= 10*3600 ? 5
274 : elapsedSecs >= 3600 ? 4
275 : elapsedSecs >= 10*60 ? 3
276 : elapsedSecs >= 60 ? 2
277 : elapsedSecs >= 9 ? 1
279 timeSize= int(autoSizes.Main.Next( AutoSizes::Types::Field, timeSize, 0 ));
282 if ( timeSize >= 4 ) dest._<NC>( elapsed.Days )._<NC>( GetFormatDate().ElapsedDays );
283 if ( timeSize >= 3 ) dest._<NC>( alib::Format(elapsed.Hours , timeSize >= 5 ? 2 : 1 ) )._<NC>( ':' );
284 if ( timeSize >= 2 ) dest._<NC>( alib::Format(elapsed.Minutes, timeSize >= 3 ? 2 : 1 ) )._<NC>( ':' );
285 dest._<NC>( alib::Format(elapsed.Seconds, timeSize >= 1 ? 2 : 1) )._<NC>( '.' );
286 dest._<NC>( alib::Format(elapsed.Milliseconds, 3) );
289 // %TL: Time elapsed since last log call
290 else if ( c2 == 'L' )
291 writeTimeDiff( dest, scope.GetTimeStamp().Since( TimeOfLastLog ).InNanoseconds() );
295 ALIB_ASSERT_WARNING( FormatWarningOnce, "ALOX",
296 "Unknown format variable
'%T{}' (only one warning)
", c2 )
297 ALIB_DBG( FormatWarningOnce= true; )
306 c2= variable.ConsumeChar();
308 if ( c2 == 'N' ) // %tN: thread name
311 const String& threadName= scope.GetThreadNameAndID(nullptr);
313 String msg( A_CHAR("SINGLE_THREADED
") );
314 const String& threadName= msg;
316 dest._<NC>( Format::Field( threadName,
318 AutoSizes::Types::Field, threadName.Length(), 0),
319 lang::Alignment::Center ) );
321 else if ( c2 == 'I' ) // %tI: thread ID
325 threadID._( scope.GetThreadID() );
329 dest._<NC>( Format::Field( threadID,
331 AutoSizes::Types::Field, threadID .Length(), 0),
332 lang::Alignment::Center ) );
336 ALIB_ASSERT_WARNING( FormatWarningOnce, "ALOX",
337 "Unknown format variable
'%t{}' (only one warning)
", c2 )
338 ALIB_DBG( FormatWarningOnce= true; )
345 c2= variable.ConsumeChar();
346 if ( c2 == 'G' ) dest._<NC>( GetName() );
347 else if ( c2 == 'X' ) dest._<NC>( scope.GetLoxName() );
350 ALIB_ASSERT_WARNING( FormatWarningOnce, "ALOX",
351 "Unknown format variable
'%L{}' (only one warning)
", c2 )
352 ALIB_DBG( FormatWarningOnce= true; )
359 dest._<NC>( ProcessInfo::Current().Name );
364 dest._<NC>( verbosity == Verbosity::Error ? fmt.VerbosityError
365 : verbosity == Verbosity::Warning ? fmt.VerbosityWarning
366 : verbosity == Verbosity::Info ? fmt.VerbosityInfo
367 : fmt.VerbosityVerbose );
372 dest._( Format::Field( domainPath,
374 AutoSizes::Types::Field, domainPath.Length(), 0 ),
375 lang::Alignment::Left ) );
380 dest._<NC>( alib::Format( CntLogs, GetFormatOther().LogNumberMinDigits ) );
386 // read extra space from format string
388 if( !variable.ConsumeDecDigits( extraSpace ) )
390 integer currentLength= dest.WStringLength();
391 integer tabPos= autoSizes.Main.Next(
392 AutoSizes::Types::Tabstop, currentLength, extraSpace);
393 dest.InsertChars(' ', tabPos - currentLength );
399 dest._<NC>( GetName() );
403 ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
404 ALIB_ASSERT_WARNING( FormatWarningOnce, "ALOX",
405 "Unknown format
character {!Q
'} (only one warning)",
406 *( variable.Buffer() -1 ) )
407 ALIB_DBG( FormatWarningOnce= true; )
408 ALIB_WARNINGS_RESTORE
413void TextLogger::writeTimeDiff( AString& buf, int64_t diffNanos )
415 auto& td= GetFormatTimeDiff();
418 if ( diffNanos < td.Minimum )
420 buf._<NC>( td.None );
424 if ( diffNanos < 1000 )
426 buf._<NC>( alib::Format( diffNanos, 3 ) )._<NC>( td.Nanos );
430 // we continue with micros
431 int64_t diffMicros= diffNanos / 1000L;
433 // below 1000 microseconds?
434 if ( diffMicros < 1000 )
436 buf._<NC>( alib::Format( diffMicros, 3 ) );
437 buf._<NC>( td.Micros );
442 if ( diffMicros < 1000000 )
444 buf._<NC>( alib::Format( (diffMicros / 1000), 3 ) )._<NC>( td.Millis );
449 // below 10 secs (rounded) ?
450 if ( diffMicros < 9995000 )
452 // convert to hundredth of secs
453 int64_t hundredthSecs= ((diffMicros / 1000) + 5) / 10;
455 // print two digits after dot x.xx
456 buf._<NC>( alib::Format( (hundredthSecs / 100), 1 ) )
458 ._<NC>( alib::Format( (hundredthSecs % 100), 2 ) )
463 // convert to tenth of secs
464 int64_t tenthSecs= ((diffMicros / 10000) + 5) / 10 ;
467 if ( tenthSecs < 1000 )
469 // print one digits after dot xx.x (round value by adding 5 hundredth)
470 buf._<NC>( alib::Format( ( tenthSecs / 10 ), 2 ) )
472 ._<NC>( alib::Format( ( tenthSecs % 10 ), 1 ) )
478 if ( tenthSecs < 6000 )
480 // convert to hundredth of minutes
481 int64_t hundredthMins= tenthSecs / 6;
483 // print two digits after dot x.xx
484 buf._<NC>( alib::Format( (hundredthMins / 100), 1 ) )
486 ._<NC>( alib::Format( (hundredthMins % 100), 2 ) )
491 // convert to tenth of minutes
492 int64_t tenthMins= tenthSecs / 60;
495 if ( tenthMins < 1000 )
497 // print one digits after dot xx.x (round value by adding 5 hundredth)
498 buf._<NC>( alib::Format( (tenthMins / 10), 2 ) )
500 ._<NC>( alib::Format( (tenthMins % 10), 1 ) )
506 if ( tenthMins < 6000 )
508 // convert to hundredth of hours
509 int64_t hundredthHours= tenthMins / 6;
511 // print two digits after dot x.xx
512 buf._<NC>( alib::Format( (hundredthHours / 100), 1 ) )
514 ._<NC>( alib::Format( (hundredthHours % 100), 2 ))
519 // convert to tenth of minutes
520 int64_t tenthHours= tenthMins / 60;
523 if ( tenthHours < 1000 )
525 // print two digits after dot x.xx
526 buf._<NC>( alib::Format( (tenthHours / 10), 2 ) )
528 ._<NC>( alib::Format( (tenthHours % 10), 1 ) )
534 if ( tenthHours < 1000 )
536 // print one digits after dot xx.x (round value by adding 5 hundredth)
537 buf._<NC>( alib::Format( (tenthHours / 10), 2 ) )
539 ._<NC>( alib::Format( ((tenthHours / 10) % 10), 1 ) )
544 // convert to hundredth of days
545 int64_t hundredthDays= tenthHours * 10 / 24;
548 if ( hundredthDays < 1000 )
550 // print two digits after dot x.xx
551 buf._<NC>( alib::Format( (hundredthDays / 100), 1 ) )
553 ._<NC>( alib::Format( (hundredthDays % 100), 2 ) )
558 // 10 days or more (print days plus one digit after the comma)
559 // print one digits after dot xx.x (round value by adding 5 hundredth)
560 buf ._<NC>( alib::Format( (hundredthDays / 100), 2 ) )
562 ._<NC>( alib::Format( ((hundredthDays / 10) % 10), 1 ) )
567// #################################################################################################
569// #################################################################################################
570TextLogger::TextLogger( const NString& pName, const NString& typeName, bool pUsesStdStreams )
571: Logger( pName, typeName )
572, usesStdStreams( pUsesStdStreams )
573, varFormatMetaInfo (alib::ALOX)
574, varFormatDateTime (alib::ALOX)
575, varFormatTimeDiff (alib::ALOX)
576, varFormatMultiLine(alib::ALOX)
577, varFormatOther (alib::ALOX)
578, varFormatAutoSizes(alib::ALOX)
579, varReplacements (alib::ALOX)
581 logBuf.SetBuffer( 256 );
582 msgBuf.SetBuffer( 256 );
585TextLogger::~TextLogger()
589 ALIB_ASSERT( msgBuf.IsEmpty() )
592void TextLogger::AcknowledgeLox( detail::LoxImpl* , lang::ContainerOp op )
594 // --------------- insert ------------------
595 if( op == lang::ContainerOp::Insert )
597 if ( Converter == nullptr )
598 Converter= new textlogger::StandardConverter();
600 // Variable AUTO_SIZES: use last session's values
603 (void) varFormatAutoSizes.Define();
610 const
Declaration* privateDecl=
ALOX.GetConfig().StoreDeclaration(variableDecl, GetName() );
612 if( !varFormatMetaInfo.Try( privateDecl )
613 && !varFormatMetaInfo.Try(
ALOX.GetConfig().StoreDeclaration(variableDecl, GetTypeName() ) ) )
615 varFormatMetaInfo.Declare( privateDecl );
617 "Mandatory (usually resourced) default value is missing for variable {!Q}.",
625 auto* privateDecl=
ALOX.GetConfig().StoreDeclaration(variableDecl, GetName() );
626 if( !varFormatDateTime.Try( privateDecl )
627 && !varFormatDateTime.Try(
ALOX.GetConfig().StoreDeclaration(variableDecl, GetTypeName() ) ) )
629 varFormatDateTime.Declare( privateDecl );
632 "Mandatory (usually resourced) default value is missing for variable {!Q}.",
640 auto* privateDecl=
ALOX.GetConfig().StoreDeclaration(variableDecl, GetName() );
641 if( !varFormatTimeDiff.Try( privateDecl )
642 && !varFormatTimeDiff.Try(
ALOX.GetConfig().StoreDeclaration(variableDecl, GetTypeName() ) ) )
644 varFormatTimeDiff.Declare( privateDecl );
646 "Mandatory (usually resourced) default value is missing for variable {!Q}.",
654 auto* privateDecl=
ALOX.GetConfig().StoreDeclaration(variableDecl, GetName() );
655 if( !varFormatMultiLine.Try( privateDecl )
656 && !varFormatMultiLine.Try(
ALOX.GetConfig().StoreDeclaration(variableDecl, GetTypeName() ) ) )
658 varFormatMultiLine.Declare( privateDecl );
660 "Mandatory (usually resourced) default value is missing for variable {!Q}.",
668 auto* privateDecl=
ALOX.GetConfig().StoreDeclaration(variableDecl, GetName() );
669 if( !varFormatOther.Try( privateDecl )
670 && !varFormatOther.Try(
ALOX.GetConfig().StoreDeclaration(variableDecl, GetTypeName() ) ) )
672 varFormatOther.Declare( privateDecl );
674 "Mandatory (usually resourced) default value is missing for variable {!Q}.",
682 auto* privateDecl =
ALOX.GetConfig().StoreDeclaration(variableDecl, GetName() );
683 if( !varReplacements.Try( privateDecl)
684 && !varReplacements.Try(
ALOX.GetConfig().StoreDeclaration(variableDecl, GetTypeName())) )
686 varReplacements.Declare(privateDecl);
691 if( !varReplacements.IsDefined() )
692 (
void) varReplacements.Define(Priority::DefaultValues - 1);
702 for(
auto it= replacements.begin(); it < replacements.end(); it+= 2)
703 if ( it->Equals<
NC>( searched ) )
708 (*it).Reset( replacement );
712 replacements.erase( it );
713 replacements.erase( it );
720 replacements.insert( replacements.end(),
AStringPA(replacements.get_allocator().GetAllocator()) );
721 replacements.back() << searched;
722 replacements.insert( replacements.end(),
AStringPA(replacements.get_allocator().GetAllocator()) );
723 replacements.back() << replacement;
749 for (
size_t i= 0; i < replacements.size() ; i+= 2 )
758 autoSizes.LogMessage.WriteProtected=
true;
762 autoSizes.Main.Restart();
783 if ( multiLine.Mode == 0 )
787 if ( multiLine.Delimiter.IsNotNull() )
791 String replacement= multiLine.DelimiterReplacement;
798 if ( cntReplacements == 0 )
820 auto prevIndex= autoSizes.Main.ActualIndex;
833 if (multiLine.Delimiter.IsEmpty() )
838 if( actEnd > actStart )
849 delimLen= multiLine.Delimiter.Length();
891 if ( lineNo == 0 && ( multiLine.Mode == 3 || multiLine.Mode == 4 ) )
894 if ( multiLine.Mode == 3 )
897 autoSizes.Main.ActualIndex= prevIndex;
902 lbLenBeforeMsgPart= 0;
906 if ( multiLine.Mode == 2 )
911 autoSizes.Main.ActualIndex= prevIndex;
918 autoSizes.Main.ActualIndex= prevIndex;
925 actStart= actEnd + delimLen;
948 if( autoSizes.Main .IsChanged()
949 || autoSizes.LogMessage.IsChanged() )
ALIB_API bool Define(Priority requestedPriority=Priority::Standard)
Priority GetPriority() const
threads::SharedLock & GetConfigLock()
static constexpr character EOMETA[4]
End of meta-information in log string.
virtual void ResetAutoSizes()=0
virtual void ConvertObjects(AString &target, BoxesMA &logables)=0
ALIB_API StandardConverter()
Constructor.
std::vector< Formatter * > Formatters
virtual ALIB_API void ConvertObjects(AString &target, BoxesMA &logables) override
virtual ALIB_API ~StandardConverter() override
Virtual destructor.
int cntRecursion
A counter to detect recursive calls.
virtual ALIB_API void ClearReplacements()
Removes all pairs of searched strings and their replacement value.
AString logBuf
The internal log Buffer.
Variable varFormatMultiLine
virtual void notifyMultiLineOp(lang::Phase phase)=0
Variable varFormatAutoSizes
virtual ALIB_API void ResetAutoSizes()
ObjectConverter * Converter
Variable varFormatMetaInfo
virtual ALIB_API void writeMetaInfo(AString &buffer, detail::Domain &domain, Verbosity verbosity, detail::ScopeInfo &scope)
Replacements & GetReplacements()
AString msgBuf
The buffers for converting the logables.
virtual ALIB_API void SetReplacement(const String &searched, const String &replacement)
virtual ALIB_API void Log(detail::Domain &domain, Verbosity verbosity, BoxesMA &logables, detail::ScopeInfo &scope) override
virtual void logText(detail::Domain &domain, Verbosity verbosity, AString &msg, detail::ScopeInfo &scope, int lineNumber)=0
TAString & ShortenTo(integer newLength)
ALIB_API integer SearchAndReplace(TChar needle, TChar replacement, integer startIdx=0, integer endIdx=strings::MAX_LEN)
TAString & _(const TString< TChar > &src, integer regionStart, integer regionLength=MAX_LEN)
integer IndexOf(TChar needle, integer startIdx=0) const
TChar CharAt(integer idx) const
constexpr integer Length() const
constexpr bool IsNotNull() const
#define ALIB_ASSERT_ERROR(cond,...)
#define ALIB_ASSERT_WARNING(cond,...)
#define ALIB_LOCK_WITH(lock)
@ Begin
The start of a transaction.
@ End
The end of a transaction.
This namespaces defines class TextLogger and its helpers.
@ FORMAT_TIME_DIFF
Denotes configuration variable ALOX/LOGGERNAME/FORMAT_TIME_DIFF used by class TextLogger.
@ FORMAT
Denotes configuration variable ALOX/LOGGERNAME/FORMAT used by class TextLogger.
@ REPLACEMENTS
Denotes configuration variable ALOX/LOGGERNAME/REPLACEMENTS used by class TextLogger.
@ FORMAT_DATE_TIME
Denotes configuration variable ALOX/LOGGERNAME/FORMAT_DATE_TIME used by class TextLogger.
@ FORMAT_MULTILINE
Denotes configuration variable ALOX/LOGGERNAME/FORMAT_MULTILINE used by class TextLogger.
@ FORMAT_OTHER
Denotes configuration variable ALOX/LOGGERNAME/FORMAT_OTHER used by class TextLogger.
@ AUTO_SIZES
Denotes configuration variable ALOX/LOGGERNAME/AUTO_SIZES used by class TextLogger.
ALIB_API Lock STD_IOSTREAMS_LOCK
lox::ALoxCamp ALOX
The singleton instance of ALib Camp class ALoxCamp.
lang::format::FormatterPythonStyle FormatterPythonStyle
Type alias in namespace alib.
config::Declaration Declaration
Type alias in namespace alib.
characters::character character
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
AutoSizes Main
The instance used with the meta info format string.
std::vector< AStringPA, lang::StdContainerAllocator< AStringPA, PoolAllocator > > Pairs
The list of pairs of replacement strings.