about summary refs log blame commit diff
path: root/third_party/nix/src/libutil/logging.hh
blob: 8b04dfd17ee302fc1907c79c028efdf8fcd762d4 (plain) (tree)
1
2
3
4
5
6
7






                   






               

            
              











                         

               
              







                            

             
                            
 

                         
 









                                                        
 
                                    
 
                      
 
                                                                
 
                                                          
 
                                            
 


                                                                              
 
                                              
 
                                                                               

  

                                                 
 

                 
 
                      
 


                                                                        
 


                                                                                
 
                                         
 
              
 



                                                                               
 


                                                                 
 





                                                           
 


                                                                    
 
                      

  





                                                            

  
                      
 
                            
 
                                           
 


                                                                      
 

                                                      


                                                                     





                                      
 

                                                    
                                                            
                                               
                                               
 




                                                       

 
                                                          
 
                                    
 
                   
#pragma once

#include "types.hh"

namespace nix {

typedef enum {
  lvlError = 0,
  lvlWarn,
  lvlInfo,
  lvlTalkative,
  lvlChatty,
  lvlDebug,
  lvlVomit
} Verbosity;

typedef enum {
  actUnknown = 0,
  actCopyPath = 100,
  actDownload = 101,
  actRealise = 102,
  actCopyPaths = 103,
  actBuilds = 104,
  actBuild = 105,
  actOptimiseStore = 106,
  actVerifyPaths = 107,
  actSubstitute = 108,
  actQueryPathInfo = 109,
  actPostBuildHook = 110,
} ActivityType;

typedef enum {
  resFileLinked = 100,
  resBuildLogLine = 101,
  resUntrustedPath = 102,
  resCorruptedPath = 103,
  resSetPhase = 104,
  resProgress = 105,
  resSetExpected = 106,
  resPostBuildLogLine = 107,
} ResultType;

typedef uint64_t ActivityId;

class Logger {
  friend struct Activity;

 public:
  struct Field {
    // FIXME: use std::variant.
    enum { tInt = 0, tString = 1 } type;
    uint64_t i = 0;
    std::string s;
    Field(const std::string& s) : type(tString), s(s) {}
    Field(const char* s) : type(tString), s(s) {}
    Field(const uint64_t& i) : type(tInt), i(i) {}
  };

  typedef std::vector<Field> Fields;

  virtual ~Logger() {}

  virtual void log(Verbosity lvl, const FormatOrString& fs) = 0;

  void log(const FormatOrString& fs) { log(lvlInfo, fs); }

  virtual void warn(const std::string& msg);

  virtual void startActivity(ActivityId act, Verbosity lvl, ActivityType type,
                             const std::string& s, const Fields& fields,
                             ActivityId parent){};

  virtual void stopActivity(ActivityId act){};

  virtual void result(ActivityId act, ResultType type, const Fields& fields){};
};

ActivityId getCurActivity();
void setCurActivity(const ActivityId activityId);

struct Activity {
  Logger& logger;

  const ActivityId id;

  Activity(Logger& logger, Verbosity lvl, ActivityType type,
           const std::string& s = "", const Logger::Fields& fields = {},
           ActivityId parent = getCurActivity());

  Activity(Logger& logger, ActivityType type, const Logger::Fields& fields = {},
           ActivityId parent = getCurActivity())
      : Activity(logger, lvlError, type, "", fields, parent){};

  Activity(const Activity& act) = delete;

  ~Activity();

  void progress(uint64_t done = 0, uint64_t expected = 0, uint64_t running = 0,
                uint64_t failed = 0) const {
    result(resProgress, done, expected, running, failed);
  }

  void setExpected(ActivityType type2, uint64_t expected) const {
    result(resSetExpected, type2, expected);
  }

  template <typename... Args>
  void result(ResultType type, const Args&... args) const {
    Logger::Fields fields;
    nop{(fields.emplace_back(Logger::Field(args)), 1)...};
    result(type, fields);
  }

  void result(ResultType type, const Logger::Fields& fields) const {
    logger.result(id, type, fields);
  }

  friend class Logger;
};

struct PushActivity {
  const ActivityId prevAct;
  PushActivity(ActivityId act) : prevAct(getCurActivity()) {
    setCurActivity(act);
  }
  ~PushActivity() { setCurActivity(prevAct); }
};

extern Logger* logger;

Logger* makeDefaultLogger();

Logger* makeJSONLogger(Logger& prevLogger);

bool handleJSONLogMessage(const std::string& msg, const Activity& act,
                          std::map<ActivityId, Activity>& activities,
                          bool trusted);

extern Verbosity verbosity; /* suppress msgs > this */

/* Print a message if the current log level is at least the specified
   level. Note that this has to be implemented as a macro to ensure
   that the arguments are evaluated lazily. */
#define printMsg(level, args...)     \
  do {                               \
    if (level <= nix::verbosity) {   \
      logger->log(level, fmt(args)); \
    }                                \
  } while (0)

#define printError(args...) printMsg(lvlError, args)
#define printInfo(args...) printMsg(lvlInfo, args)
#define printTalkative(args...) printMsg(lvlTalkative, args)
#define debug(args...) printMsg(lvlDebug, args)
#define vomit(args...) printMsg(lvlVomit, args)

template <typename... Args>
inline void warn(const std::string& fs, Args... args) {
  boost::format f(fs);
  nop{boost::io::detail::feed(f, args)...};
  logger->warn(f.str());
}

void warnOnce(bool& haveWarned, const FormatOrString& fs);

void writeToStderr(const string& s);

}  // namespace nix