diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/actors/core/log_settings.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/actors/core/log_settings.h')
-rw-r--r-- | library/cpp/actors/core/log_settings.h | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/library/cpp/actors/core/log_settings.h b/library/cpp/actors/core/log_settings.h new file mode 100644 index 0000000000..7fe4504edd --- /dev/null +++ b/library/cpp/actors/core/log_settings.h @@ -0,0 +1,176 @@ +#pragma once + +#include "actor.h" +#include "log_iface.h" +#include <util/generic/vector.h> +#include <util/digest/murmur.h> +#include <util/random/easy.h> + +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<const TString&(EComponent)>; + ; + + // 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<TAtomic> ComponentInfo; + TVector<TString> 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 <typename T> + void Append(T minVal, T maxVal, const TString& (*func)(T)) { + Append( + static_cast<EComponent>(minVal), + static_cast<EComponent>(maxVal), + [func](EComponent c) -> const TString& { + return func(static_cast<T>(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<ui32>((const char*)&sampleBy, sizeof(sampleBy)) + : samplingRate != 1 ? RandomNumber<ui32>() : 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); + }; + + } + +} |