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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <config.h>
#include <process/logging_info.h>
#include <process/daemon.h>
#include <log/logger_name.h>

using namespace isc::log;
using namespace isc::data;

namespace isc {
namespace process {

static const std::string STDOUT = "stdout";
static const std::string STDERR = "stderr";
static const std::string SYSLOG = "syslog";
static const std::string SYSLOG_COLON = "syslog:";

bool
LoggingDestination::equals(const LoggingDestination& other) const {
    return (output_ == other.output_ &&
            maxver_ == other.maxver_ &&
            maxsize_ == other.maxsize_ &&
            flush_ == other.flush_ &&
            pattern_ == other.pattern_);
}

ElementPtr
LoggingDestination::toElement() const {
    ElementPtr result = Element::createMap();

    // Set output
    result->set("output", Element::create(output_));

    // Set flush
    result->set("flush", Element::create(flush_));

    // Set pattern
    result->set("pattern", Element::create(pattern_));

    if ((output_ != STDOUT) && (output_ != STDERR) && (output_ != SYSLOG) &&
        (output_.find(SYSLOG_COLON) == std::string::npos)) {
        // Set maxver
        result->set("maxver", Element::create(maxver_));

        // Set maxsize
        result->set("maxsize", Element::create(static_cast<long long>(maxsize_)));
    }

    return (result);
}

LoggingInfo::LoggingInfo()
    : name_("kea"), severity_(isc::log::INFO), debuglevel_(0) {
    // If configuration Manager is in the verbose mode, we need to modify the
    // default settings.
    if (Daemon::getVerbose()) {
        severity_ = isc::log::DEBUG;
        debuglevel_ = 99;
    }

    // If the process has set the non-empty name for the default logger,
    // let's use this name.
    std::string default_logger = Daemon::getDefaultLoggerName();
    if (!default_logger.empty()) {
        name_ = default_logger;
    }

    // Add a default logging destination in case use hasn't provided a
    // logger specification.
    LoggingDestination dest;
    dest.output_ = "stdout";
    destinations_.push_back(dest);
}

bool
LoggingInfo::equals(const LoggingInfo& other) const {
    // If number of destinations aren't equal, the objects are not equal.
    if (destinations_.size() != other.destinations_.size()) {
        return (false);
    }
    // If there is the same number of logging destinations verify that the
    // destinations are equal. The order doesn't matter to we don't expect
    // that they are at the same index of the vectors.
    for (auto const& dest : destinations_) {
        bool match = false;
        for (auto const& dest_other : other.destinations_) {
            if (dest.equals(dest_other)) {<--- Consider using std::any_of algorithm instead of a raw loop.
                match = true;
                break;
            }
        }
        if (!match) {
            return (false);
        }
    }

    // Logging destinations are equal. Check the rest of the parameters for
    // equality.
    return (name_ == other.name_ &&
            severity_ == other.severity_ &&
            debuglevel_ == other.debuglevel_);
}

LoggerSpecification
LoggingInfo::toSpec() const {
    LoggerSpecification spec(name_, severity_, debuglevel_);

    // Go over logger destinations and create output options accordingly.
    for (auto const& dest : destinations_) {
        OutputOption option;
        // Set up output option according to destination specification
        if (dest.output_ == STDOUT) {
            option.destination = OutputOption::DEST_CONSOLE;
            option.stream = OutputOption::STR_STDOUT;

        } else if (dest.output_ == STDERR) {
            option.destination = OutputOption::DEST_CONSOLE;
            option.stream = OutputOption::STR_STDERR;

        } else if (dest.output_ == SYSLOG) {
            option.destination = OutputOption::DEST_SYSLOG;
            // Use default specified in OutputOption constructor for the
            // syslog destination

        } else if (dest.output_.find(SYSLOG_COLON) == 0) {
            option.destination = OutputOption::DEST_SYSLOG;
            // Must take account of the string actually being "syslog:"
            if (dest.output_ == SYSLOG_COLON) {
                // The expected syntax is syslog:facility. User skipped
                // the logging name, so we'll just use the default ("kea")
                option.facility = isc::log::getDefaultRootLoggerName();

            } else {
                // Everything else in the string is the facility name
                option.facility = dest.output_.substr(SYSLOG_COLON.size());
            }

        } else {
            // Not a recognized destination, assume a file.
            option.destination = OutputOption::DEST_FILE;
            option.filename = dest.output_;
            option.maxsize = dest.maxsize_;
            option.maxver = dest.maxver_;
        }

        // Copy the immediate flush flag
        option.flush = dest.flush_;

        // Copy the pattern
        option.pattern = dest.pattern_;

        // ... and set the destination
        spec.addOutputOption(option);
    }

    return (spec);
}

ElementPtr
LoggingInfo::toElement() const {
    ElementPtr result = Element::createMap();
    // Set user context
    contextToElement(result);
    // Set name
    result->set("name", Element::create(name_));
    // Set output-options if not empty
    if (!destinations_.empty()) {
        ElementPtr options = Element::createList();
        for (auto const& dest : destinations_) {
            options->add(dest.toElement());
        }
        result->set("output-options", options);
    }
    // Set severity
    std::string severity;
    switch (severity_) {
    case isc::log::DEBUG:
        severity = "DEBUG";
        break;
    case isc::log::INFO:
        severity = "INFO";
        break;
    case isc::log::WARN:
        severity = "WARN";
        break;
    case isc::log::ERROR:
        severity = "ERROR";
        break;
    case isc::log::FATAL:
        severity = "FATAL";
        break;
    case isc::log::NONE:
        severity = "NONE";
        break;
    default:
        isc_throw(ToElementError, "illegal severity: " << severity_);
        break;
    }
    result->set("severity", Element::create(severity));
    // Set debug level
    result->set("debuglevel", Element::create(debuglevel_));

    return (result);
}

} // end of namespace isc::dhcp
} // end of namespace isc