about summary refs log tree commit diff
path: root/src/libutil/logging.cc
blob: ed83770a14aa197b07d5d1f0e9d3038dff9f0727 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "logging.hh"
#include "util.hh"

#include <atomic>

namespace nix {

Logger * logger = makeDefaultLogger();

void Logger::warn(const std::string & msg)
{
    log(lvlInfo, ANSI_RED "warning:" ANSI_NORMAL " " + msg);
}

class SimpleLogger : public Logger
{
public:

    bool systemd, tty;

    SimpleLogger()
    {
        systemd = getEnv("IN_SYSTEMD") == "1";
        tty = isatty(STDERR_FILENO);
    }

    void log(Verbosity lvl, const FormatOrString & fs) override
    {
        if (lvl > verbosity) return;

        std::string prefix;

        if (systemd) {
            char c;
            switch (lvl) {
            case lvlError: c = '3'; break;
            case lvlInfo: c = '5'; break;
            case lvlTalkative: case lvlChatty: c = '6'; break;
            default: c = '7';
            }
            prefix = std::string("<") + c + ">";
        }

        writeToStderr(prefix + (tty ? fs.s : filterANSIEscapes(fs.s)) + "\n");
    }

    void event(const Event & ev) override
    {
    }
};

Verbosity verbosity = lvlInfo;

void warnOnce(bool & haveWarned, const FormatOrString & fs)
{
    if (!haveWarned) {
        warn(fs.s);
        haveWarned = true;
    }
}

void writeToStderr(const string & s)
{
    try {
        writeFull(STDERR_FILENO, s, false);
    } catch (SysError & e) {
        /* Ignore failing writes to stderr.  We need to ignore write
           errors to ensure that cleanup code that logs to stderr runs
           to completion if the other side of stderr has been closed
           unexpectedly. */
    }
}

Logger * makeDefaultLogger()
{
    return new SimpleLogger();
}

std::atomic<uint64_t> nextId{(uint64_t) getpid() << 32};

Activity::Activity() : id(nextId++) { };

Activity::Activity(ActivityType type, std::string msg)
    : Activity()
{
    logger->event(evStartActivity, id, type, msg);
}

Activity::~Activity()
{
    logger->event(evStopActivity, id);
}

void Activity::progress(uint64_t done, uint64_t expected, uint64_t running, uint64_t failed) const
{
    logger->event(evProgress, id, done, expected, running, failed);
}

}