#pragma once #include "actor.h" #include "log_iface.h" #include #include #include namespace NActors { namespace NLog { inline const char* PriorityToString(EPrio priority) { switch (priority) { case EPrio::Emerg: return "EMERG"; case EPrio::Alert: return "ALERT"; case EPrio::Crit: return "CRIT"; case EPrio::Error: return "ERROR"; case EPrio::Warn: return "WARN"; case EPrio::Notice: return "NOTICE"; case EPrio::Info: return "INFO"; case EPrio::Debug: return "DEBUG"; case EPrio::Trace: return "TRACE"; default: return "UNKNOWN"; } } // You can structure your program to have multiple logical components. // In this case you can set different log priorities for different // components. And you can change component's priority while system // is running. Suspect a component has a bug? Turn DEBUG priority level on // for this component. static const int InvalidComponent = -1; // Functions converts EComponent id to string using EComponentToStringFunc = std::function; ; // Log settings struct TComponentSettings { union { struct { ui32 SamplingRate; ui8 SamplingLevel; ui8 Level; } X; ui64 Data; } Raw; TComponentSettings(TAtomicBase data) { Raw.Data = (ui64)data; } TComponentSettings(ui8 level, ui8 samplingLevel, ui32 samplingRate) { Raw.X.Level = level; Raw.X.SamplingLevel = samplingLevel; Raw.X.SamplingRate = samplingRate; } }; struct TSettings: public TThrRefBase { public: TActorId LoggerActorId; EComponent LoggerComponent; ui64 TimeThresholdMs; bool AllowDrop; TDuration ThrottleDelay; TArrayHolder ComponentInfo; TVector ComponentNames; EComponent MinVal; EComponent MaxVal; EComponent Mask; EPriority DefPriority; EPriority DefSamplingPriority; ui32 DefSamplingRate; bool UseLocalTimestamps; enum ELogFormat { PLAIN_FULL_FORMAT, PLAIN_SHORT_FORMAT, JSON_FORMAT }; ELogFormat Format; TString ShortHostName; TString ClusterName; TString MessagePrefix; // The best way to provide minVal, maxVal and func is to have // protobuf enumeration of components. In this case protoc // automatically generates YOURTYPE_MIN, YOURTYPE_MAX and // YOURTYPE_Name for you. TSettings(const TActorId& loggerActorId, const EComponent loggerComponent, EComponent minVal, EComponent maxVal, EComponentToStringFunc func, EPriority defPriority, EPriority defSamplingPriority = PRI_DEBUG, ui32 defSamplingRate = 0, ui64 timeThresholdMs = 1000); TSettings(const TActorId& loggerActorId, const EComponent loggerComponent, EPriority defPriority, EPriority defSamplingPriority = PRI_DEBUG, ui32 defSamplingRate = 0, ui64 timeThresholdMs = 1000); void Append(EComponent minVal, EComponent maxVal, EComponentToStringFunc func); template void Append(T minVal, T maxVal, const TString& (*func)(T)) { Append( static_cast(minVal), static_cast(maxVal), [func](EComponent c) -> const TString& { return func(static_cast(c)); } ); } inline bool Satisfies(EPriority priority, EComponent component, ui64 sampleBy = 0) const { // by using Mask we don't get outside of array boundaries TComponentSettings settings = GetComponentSettings(component); if (priority > settings.Raw.X.Level) { if (priority > settings.Raw.X.SamplingLevel) { return false; // priority > both levels ==> do not log } // priority <= sampling level ==> apply sampling ui32 samplingRate = settings.Raw.X.SamplingRate; if (samplingRate) { ui32 samplingValue = sampleBy ? MurmurHash((const char*)&sampleBy, sizeof(sampleBy)) : samplingRate != 1 ? RandomNumber() : 0; return (samplingValue % samplingRate == 0); } else { // sampling rate not set ==> do not log return false; } } else { // priority <= log level ==> log return true; } } inline TComponentSettings GetComponentSettings(EComponent component) const { Y_VERIFY_DEBUG((component & Mask) == component); // by using Mask we don't get outside of array boundaries return TComponentSettings(AtomicGet(ComponentInfo[component & Mask])); } const char* ComponentName(EComponent component) const { Y_VERIFY_DEBUG((component & Mask) == component); return ComponentNames[component & Mask].data(); } int SetLevel(EPriority priority, EComponent component, TString& explanation); int SetSamplingLevel(EPriority priority, EComponent component, TString& explanation); int SetSamplingRate(ui32 sampling, EComponent component, TString& explanation); EComponent FindComponent(const TStringBuf& componentName) const; static int PowerOf2Mask(int val); static bool IsValidPriority(EPriority priority); bool IsValidComponent(EComponent component); void SetAllowDrop(bool val); void SetThrottleDelay(TDuration value); void SetUseLocalTimestamps(bool value); private: int SetLevelImpl( const TString& name, bool isSampling, EPriority priority, EComponent component, TString& explanation); }; } }