aboutsummaryrefslogtreecommitdiff
path: root/src/common/logging/backend.h
blob: e5d702568fed78131633fcfd606236a5fefd46f2 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once

#include <chrono>
#include <memory>
#include <string>
#include <string_view>
#include "common/file_util.h"
#include "common/logging/filter.h"
#include "common/logging/log.h"

namespace Log {

class Filter;

/**
 * A log entry. Log entries are store in a structured format to permit more varied output
 * formatting on different frontends, as well as facilitating filtering and aggregation.
 */
struct Entry {
    std::chrono::microseconds timestamp;
    Class log_class{};
    Level log_level{};
    const char* filename = nullptr;
    unsigned int line_num = 0;
    std::string function;
    std::string message;
    bool final_entry = false;
};

/**
 * Interface for logging backends. As loggers can be created and removed at runtime, this can be
 * used by a frontend for adding a custom logging backend as needed
 */
class Backend {
public:
    virtual ~Backend() = default;
    virtual void SetFilter(const Filter& new_filter) {
        filter = new_filter;
    }
    virtual const char* GetName() const = 0;
    virtual void Write(const Entry& entry) = 0;

private:
    Filter filter;
};

/**
 * Backend that writes to stderr without any color commands
 */
class ConsoleBackend : public Backend {
public:
    static const char* Name() {
        return "console";
    }
    const char* GetName() const override {
        return Name();
    }
    void Write(const Entry& entry) override;
};

/**
 * Backend that writes to stderr and with color
 */
class ColorConsoleBackend : public Backend {
public:
    static const char* Name() {
        return "color_console";
    }

    const char* GetName() const override {
        return Name();
    }
    void Write(const Entry& entry) override;
};

/**
 * Backend that writes to a file passed into the constructor
 */
class FileBackend : public Backend {
public:
    explicit FileBackend(const std::string& filename);

    static const char* Name() {
        return "file";
    }

    const char* GetName() const override {
        return Name();
    }

    void Write(const Entry& entry) override;

private:
    FileUtil::IOFile file;
    std::size_t bytes_written;
};

/**
 * Backend that writes to Visual Studio's output window
 */
class DebuggerBackend : public Backend {
public:
    static const char* Name() {
        return "debugger";
    }
    const char* GetName() const override {
        return Name();
    }
    void Write(const Entry& entry) override;
};

void AddBackend(std::unique_ptr<Backend> backend);

void RemoveBackend(std::string_view backend_name);

Backend* GetBackend(std::string_view backend_name);

/**
 * Returns the name of the passed log class as a C-string. Subclasses are separated by periods
 * instead of underscores as in the enumeration.
 */
const char* GetLogClassName(Class log_class);

/**
 * Returns the name of the passed log level as a C-string.
 */
const char* GetLevelName(Level log_level);

/**
 * The global filter will prevent any messages from even being processed if they are filtered. Each
 * backend can have a filter, but if the level is lower than the global filter, the backend will
 * never get the message
 */
void SetGlobalFilter(const Filter& filter);
} // namespace Log