aboutsummaryrefslogblamecommitdiffstats
path: root/library/cpp/actors/core/log.h
blob: c11a7cf3c191eb3dcb2deff342d7cd654dcb23e7 (plain) (tree)
1
2
3
4
5
            
                 
 
                      







                                
                                
                                   
                                                         
                                                       
                                              
 
                                                 


                                                                 






                                                                                                  








                                                                                                                                
 
                                                                                        
                                                                                       

                                                                                        
               

                                                                                                                                          
 
                                                                 







                                                                                                                                 
 



                                                                                                                                 
                                                                                                                                   

                                                                                                                                 
 







                                                                                                                                                                           
 



                                                                                                                                                                           
                                                                                                                                                                             

                                                                                                                                                                           
 
                                                                                 



                                                                                 
 





                                                                                                                                                          
                                                                                                                                                    
     
                                                                                                                                       
 







                                                                                    
                                                                                                              




















                                                                                       
                                                                                                                 
           
                                                                        







                                      
                                               



                               
                            
      
                                                                                 



                       

                                                                                    














                                                       
           


                                                                    
                                                             
                                                                            

                                                                            




                                                                            
                        
                                                                              
                                           
                                                       
                                                    



                                                                                 








                                                                                 
                                                            
                                                                                                          
 
                                                              
 
                                                

                                                
                                  
                                                        
                                                
 
                             
                                                                                          
                                      
                                                                              
                                                              
                                                                                                           
                                                                                                                                            
                                                           
                                           
                                                      
                                                                          












                                                                                    
         




















                                                                                    
                                                                   
                                                                            
                                                
                                                                     
                                              
                                                                                                         
 

                                                                         
 











                                                                                          
                            

                                                                                                                   
                                           
                                                                                                                                  
     
                                               
                              

                                    
                                                
                          
 




                                                                                
                                                              
                                                                                         

                            



                                        










                                                                                 
                                                  
                                                                                   
     
 
#pragma once

#include "defs.h"

#include "log_iface.h"
#include "log_settings.h"
#include "actorsystem.h"
#include "events.h"
#include "event_local.h"
#include "hfunc.h"
#include "mon.h"

#include <util/generic/vector.h>
#include <util/string/printf.h>
#include <util/string/builder.h>
#include <library/cpp/logger/all.h>
#include <library/cpp/monlib/dynamic_counters/counters.h>
#include <library/cpp/monlib/metrics/metric_registry.h>
#include <library/cpp/json/writer/json.h>
#include <library/cpp/svnversion/svnversion.h>

#include <library/cpp/actors/memory_log/memlog.h>

// TODO: limit number of messages per second
// TODO: make TLogComponentLevelRequest/Response network messages

#define IS_LOG_PRIORITY_ENABLED(actorCtxOrSystem, priority, component)                           \
    (static_cast<::NActors::NLog::TSettings*>((actorCtxOrSystem).LoggerSettings()) &&            \
     static_cast<::NActors::NLog::TSettings*>((actorCtxOrSystem).LoggerSettings())->Satisfies(   \
             static_cast<::NActors::NLog::EPriority>(priority),                                  \
             static_cast<::NActors::NLog::EComponent>(component),                                \
             0ull)                                                                               \
    )

#define LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, ...)                                               \
    do {                                                                                                                       \
        ::NActors::NLog::TSettings* mSettings = static_cast<::NActors::NLog::TSettings*>((actorCtxOrSystem).LoggerSettings()); \
        ::NActors::NLog::EPriority mPriority = static_cast<::NActors::NLog::EPriority>(priority);                              \
        ::NActors::NLog::EComponent mComponent = static_cast<::NActors::NLog::EComponent>(component);                          \
        if (mSettings && mSettings->Satisfies(mPriority, mComponent, sampleBy)) {                                              \
            ::NActors::MemLogAdapter(                                                                                          \
                actorCtxOrSystem, priority, component, __VA_ARGS__);                                                           \
        }                                                                                                                      \
    } while (0) /**/

#define LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, stream)  \
    LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, sampleBy, "%s", [&]() { \
        TStringBuilder logStringBuilder;                                               \
        logStringBuilder << stream;                                                    \
        return static_cast<TString>(logStringBuilder);                                 \
    }().data())

#define LOG_LOG(actorCtxOrSystem, priority, component, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, priority, component, 0ull, __VA_ARGS__)
#define LOG_LOG_S(actorCtxOrSystem, priority, component, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, priority, component, 0ull, stream)

// use these macros for logging via actor system or actor context
#define LOG_EMERG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, __VA_ARGS__)
#define LOG_ALERT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, __VA_ARGS__)
#define LOG_CRIT(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, __VA_ARGS__)
#define LOG_ERROR(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, __VA_ARGS__)
#define LOG_WARN(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, __VA_ARGS__)
#define LOG_NOTICE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, __VA_ARGS__)
#define LOG_INFO(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, __VA_ARGS__)
#define LOG_DEBUG(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, __VA_ARGS__)
#define LOG_TRACE(actorCtxOrSystem, component, ...) LOG_LOG(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, __VA_ARGS__)

#define LOG_EMERG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, stream)
#define LOG_ALERT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, stream)
#define LOG_CRIT_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, stream)
#define LOG_ERROR_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, stream)
#define LOG_WARN_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, stream)
#define LOG_NOTICE_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, stream)
#define LOG_INFO_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, stream)
#define LOG_DEBUG_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, stream)
#define LOG_TRACE_S(actorCtxOrSystem, component, stream) LOG_LOG_S(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, stream)

#define LOG_EMERG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, __VA_ARGS__)
#define LOG_ALERT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, __VA_ARGS__)
#define LOG_CRIT_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, __VA_ARGS__)
#define LOG_ERROR_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, __VA_ARGS__)
#define LOG_WARN_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, __VA_ARGS__)
#define LOG_NOTICE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, sampleBy, __VA_ARGS__)
#define LOG_INFO_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, __VA_ARGS__)
#define LOG_DEBUG_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, __VA_ARGS__)
#define LOG_TRACE_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, ...) LOG_LOG_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, __VA_ARGS__)

#define LOG_EMERG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_EMERG, component, sampleBy, stream)
#define LOG_ALERT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ALERT, component, sampleBy, stream)
#define LOG_CRIT_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_CRIT, component, sampleBy, stream)
#define LOG_ERROR_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_ERROR, component, sampleBy, stream)
#define LOG_WARN_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_WARN, component, sampleBy, stream)
#define LOG_NOTICE_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_NOTICE, component, sampleBy, stream)
#define LOG_INFO_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_INFO, component, sampleBy, stream)
#define LOG_DEBUG_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_DEBUG, component, sampleBy, stream)
#define LOG_TRACE_S_SAMPLED_BY(actorCtxOrSystem, component, sampleBy, stream) LOG_LOG_S_SAMPLED_BY(actorCtxOrSystem, NActors::NLog::PRI_TRACE, component, sampleBy, stream)

// Log Throttling
#define LOG_LOG_THROTTLE(throttler, actorCtxOrSystem, priority, component, ...) \
    do {                                                                        \
        if ((throttler).Kick()) {                                               \
            LOG_LOG(actorCtxOrSystem, priority, component, __VA_ARGS__);        \
        }                                                                       \
    } while (0) /**/

#define TRACE_EVENT(component)                                                                                                         \
    const auto& currentTracer = component;                                                                                             \
    if (ev->HasEvent()) {                                                                                                              \
        LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s: %s",                                  \
                  __FUNCTION__, ev->Type, ev->Sender.ToString().data(), SelfId().ToString().data(), ev->GetBase()->ToString().substr(0, 1000).data()); \
    } else {                                                                                                                           \
        LOG_TRACE(*TlsActivationContext, currentTracer, "%s, received event# %" PRIu32 ", Sender %s, Recipient %s",                                      \
                  __FUNCTION__, ev->Type, ev->Sender.ToString().data(), ev->Recipient.ToString().data());                                          \
    }
#define TRACE_EVENT_TYPE(eventType) LOG_TRACE(*TlsActivationContext, currentTracer, "%s, processing event %s", __FUNCTION__, eventType)

class TLog;
class TLogBackend;

namespace NActors {
    class TLoggerActor;

    ////////////////////////////////////////////////////////////////////////////////
    // SET LOG LEVEL FOR A COMPONENT
    ////////////////////////////////////////////////////////////////////////////////
    class TLogComponentLevelRequest: public TEventLocal<TLogComponentLevelRequest, int(NLog::EEv::LevelReq)> {
    public:
        // set given priority for the component
        TLogComponentLevelRequest(NLog::EPriority priority, NLog::EComponent component)
            : Priority(priority)
            , Component(component)
        {
        }

        // set given priority for all components
        TLogComponentLevelRequest(NLog::EPriority priority)
            : Priority(priority)
            , Component(NLog::InvalidComponent)
        {
        }

    protected:
        NLog::EPriority Priority;
        NLog::EComponent Component;

        friend class TLoggerActor;
    };

    class TLogComponentLevelResponse: public TEventLocal<TLogComponentLevelResponse, int(NLog::EEv::LevelResp)> {
    public:
        TLogComponentLevelResponse(int code, const TString& explanation)
            : Code(code)
            , Explanation(explanation)
        {
        }

        int GetCode() const {
            return Code;
        }

        const TString& GetExplanation() const {
            return Explanation;
        }

    protected:
        int Code;
        TString Explanation;
    };

    class TLogIgnored: public TEventLocal<TLogIgnored, int(NLog::EEv::Ignored)> {
    public:
        TLogIgnored() {
        }
    };

    ////////////////////////////////////////////////////////////////////////////////
    // LOGGER ACTOR
    ////////////////////////////////////////////////////////////////////////////////
    class ILoggerMetrics {
    public:
        virtual ~ILoggerMetrics() = default;

        virtual void IncActorMsgs() = 0;
        virtual void IncDirectMsgs() = 0;
        virtual void IncLevelRequests() = 0;
        virtual void IncIgnoredMsgs() = 0;
        virtual void IncAlertMsgs() = 0;
        virtual void IncEmergMsgs() = 0;
        virtual void IncDroppedMsgs() = 0;

        virtual void GetOutputHtml(IOutputStream&) = 0;
    };

    class TLoggerActor: public TActor<TLoggerActor> {
    public:
        static constexpr IActor::EActivityType ActorActivityType() {
            return IActor::LOG_ACTOR;
        }

        TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
                     TAutoPtr<TLogBackend> logBackend,
                     TIntrusivePtr<NMonitoring::TDynamicCounters> counters);
        TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
                     std::shared_ptr<TLogBackend> logBackend,
                     TIntrusivePtr<NMonitoring::TDynamicCounters> counters);
        TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
                     TAutoPtr<TLogBackend> logBackend,
                     std::shared_ptr<NMonitoring::TMetricRegistry> metrics);
        TLoggerActor(TIntrusivePtr<NLog::TSettings> settings,
                     std::shared_ptr<TLogBackend> logBackend,
                     std::shared_ptr<NMonitoring::TMetricRegistry> metrics);
        ~TLoggerActor();

        void StateFunc(TAutoPtr<IEventHandle>& ev, const TActorContext& ctx) {
            switch (ev->GetTypeRewrite()) {
                HFunc(TLogIgnored, HandleIgnoredEvent);
                HFunc(NLog::TEvLog, HandleLogEvent);
                HFunc(TLogComponentLevelRequest, HandleLogComponentLevelRequest);
                HFunc(NMon::TEvHttpInfo, HandleMonInfo);
            }
        }

        STFUNC(StateDefunct) {
            switch (ev->GetTypeRewrite()) {
                cFunc(TLogIgnored::EventType, HandleIgnoredEventDrop);
                hFunc(NLog::TEvLog, HandleLogEventDrop);
                HFunc(TLogComponentLevelRequest, HandleLogComponentLevelRequest);
                HFunc(NMon::TEvHttpInfo, HandleMonInfo);
                cFunc(TEvents::TEvWakeup::EventType, HandleWakeup);
            }
        }

        // Directly call logger instead of sending a message
        void Log(TInstant time, NLog::EPriority priority, NLog::EComponent component, const char* c, ...);

        static void Throttle(const NLog::TSettings& settings);

    private:
        TIntrusivePtr<NLog::TSettings> Settings;
        std::shared_ptr<TLogBackend> LogBackend;
        ui64 IgnoredCount = 0;
        ui64 PassedCount = 0;
        static TAtomic IsOverflow;
        TDuration WakeupInterval{TDuration::Seconds(5)};
        std::unique_ptr<ILoggerMetrics> Metrics;

        void BecomeDefunct();
        void HandleIgnoredEvent(TLogIgnored::TPtr& ev, const NActors::TActorContext& ctx);
        void HandleIgnoredEventDrop();
        void HandleLogEvent(NLog::TEvLog::TPtr& ev, const TActorContext& ctx);
        void HandleLogEventDrop(const NLog::TEvLog::TPtr& ev);
        void HandleLogComponentLevelRequest(TLogComponentLevelRequest::TPtr& ev, const TActorContext& ctx);
        void HandleMonInfo(NMon::TEvHttpInfo::TPtr& ev, const TActorContext& ctx);
        void HandleWakeup();
        [[nodiscard]] bool OutputRecord(TInstant time, NLog::EPrio priority, NLog::EComponent component, const TString& formatted) noexcept;
        void RenderComponentPriorities(IOutputStream& str);
        void LogIgnoredCount(TInstant now);
        void WriteMessageStat(const NLog::TEvLog& ev);
        static const char* FormatLocalTimestamp(TInstant time, char* buf);
    };

    ////////////////////////////////////////////////////////////////////////////////
    // LOG THROTTLING
    // TTrivialLogThrottler -- log a message every 'period' duration
    // Use case:
    //  TTrivialLogThrottler throttler(TDuration::Minutes(1));
    //  ....
    //  LOG_LOG_THROTTLE(throttler, ctx, NActors::NLog::PRI_ERROR, SOME, "Error");
    ////////////////////////////////////////////////////////////////////////////////
    class TTrivialLogThrottler {
    public:
        TTrivialLogThrottler(TDuration period)
            : Period(period)
        {
        }

        // return value:
        // true -- write to log
        // false -- don't write to log, throttle
        bool Kick() {
            auto now = TInstant::Now();
            if (now >= (LastWrite + Period)) {
                LastWrite = now;
                return true;
            } else {
                return false;
            }
        }

    private:
        TInstant LastWrite;
        TDuration Period;
    };

    ////////////////////////////////////////////////////////////////////////////////
    // SYSLOG BACKEND
    ////////////////////////////////////////////////////////////////////////////////
    TAutoPtr<TLogBackend> CreateSysLogBackend(const TString& ident,
                                              bool logPError, bool logCons);
    TAutoPtr<TLogBackend> CreateStderrBackend();
    TAutoPtr<TLogBackend> CreateFileBackend(const TString& fileName);
    TAutoPtr<TLogBackend> CreateNullBackend();
    TAutoPtr<TLogBackend> CreateCompositeLogBackend(TVector<TAutoPtr<TLogBackend>>&& underlyingBackends);

    /////////////////////////////////////////////////////////////////////
    //  Logging adaptors for memory log and logging into filesystem
    /////////////////////////////////////////////////////////////////////

    namespace NDetail {
        inline void Y_PRINTF_FORMAT(2, 3) PrintfV(TString& dst, const char* format, ...) {
            va_list params;
            va_start(params, format);
            vsprintf(dst, format, params);
            va_end(params);
        }

        inline void PrintfV(TString& dst, const char* format, va_list params) {
            vsprintf(dst, format, params);
        }
    } // namespace NDetail

    template <typename TCtx>
    inline void DeliverLogMessage(TCtx& ctx, NLog::EPriority mPriority, NLog::EComponent mComponent, TString &&str)
    {
        const NLog::TSettings *mSettings = ctx.LoggerSettings();
        TLoggerActor::Throttle(*mSettings);
        ctx.Send(new IEventHandle(mSettings->LoggerActorId, TActorId(), new NLog::TEvLog(mPriority, mComponent, std::move(str))));
    }

    template <typename TCtx, typename... TArgs>
    inline void MemLogAdapter(
        TCtx& actorCtxOrSystem,
        NLog::EPriority mPriority,
        NLog::EComponent mComponent,
        const char* format, TArgs&&... params) {
        TString Formatted;


        if constexpr (sizeof... (params) > 0) {
            NDetail::PrintfV(Formatted, format, std::forward<TArgs>(params)...);
        } else {
            NDetail::PrintfV(Formatted, "%s", format);
        }

        MemLogWrite(Formatted.data(), Formatted.size(), true);
        DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, std::move(Formatted));
    }

    template <typename TCtx>
    Y_WRAPPER inline void MemLogAdapter(
        TCtx& actorCtxOrSystem,
        NLog::EPriority mPriority,
        NLog::EComponent mComponent,
        const TString& str) {

        MemLogWrite(str.data(), str.size(), true);
        DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, TString(str));
    }

    template <typename TCtx>
    Y_WRAPPER inline void MemLogAdapter(
        TCtx& actorCtxOrSystem,
        NLog::EPriority mPriority,
        NLog::EComponent mComponent,
        TString&& str) {

        MemLogWrite(str.data(), str.size(), true);
        DeliverLogMessage(actorCtxOrSystem, mPriority, mComponent, std::move(str));
    }
}