Kea 3.1.1
log_parser.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8#include <cc/data.h>
9#include <process/d_log.h>
10#include <process/log_parser.h>
11#include <boost/lexical_cast.hpp>
13#include <log/logger_support.h>
14#include <log/logger_manager.h>
15#include <log/logger_name.h>
16#include <util/filesystem.h>
17
18using namespace isc::data;
19using namespace isc::log;
20using namespace isc::util::file;
21
22namespace isc {
23namespace process {
24
25namespace {
26 // Singleton PathChecker to set and hold valid log file path.
27 PathCheckerPtr log_path_checker_;
28};
29
31 :config_(storage), verbose_(false) {
32 if (!storage) {
33 isc_throw(BadValue, "LogConfigParser needs a pointer to the "
34 "configuration, so parsed data can be stored there");
35 }
36}
37
39 bool verbose) {
40 verbose_ = verbose;
41
42 // Iterate over all entries in "Server/loggers" list
43 for (auto const& logger : loggers->listValue()) {
44 parseConfigEntry(logger);
45 }
46}
47
48void LogConfigParser::parseConfigEntry(isc::data::ConstElementPtr entry) {
49 if (!entry) {
50 // This should not happen, but let's be on the safe side and check
51 return;
52 }
53
54 if (!config_) {
55 isc_throw(BadValue, "configuration storage not set, can't parse logger config.");
56 }
57
58 LoggingInfo info;
59 // Remove default destinations as we are going to replace them.
60 info.clearDestinations();
61
62 // Get user context
63 isc::data::ConstElementPtr user_context = entry->get("user-context");
64 if (user_context) {
65 info.setContext(user_context);
66 }
67
68 // Get a name
69 isc::data::ConstElementPtr name_ptr = entry->get("name");
70 if (!name_ptr) {
71 isc_throw(BadValue, "loggers entry does not have a mandatory 'name' "
72 "element (" << entry->getPosition() << ")");
73 }
74 info.name_ = name_ptr->stringValue();
75
76 // Get the severity.
77 // If not configured, set it to DEFAULT to inherit it from the root logger later.
78 isc::data::ConstElementPtr severity_ptr = entry->get("severity");
79 if (severity_ptr) {
80 info.severity_ = getSeverity(severity_ptr->stringValue());
81 } else {
82 info.severity_ = DEFAULT;
83 }
84
85 // Get debug logging level
86 info.debuglevel_ = 0;
87 isc::data::ConstElementPtr debuglevel_ptr = entry->get("debuglevel");
88
89 // It's ok to not have debuglevel, we'll just assume its least verbose
90 // (0) level.
91 if (debuglevel_ptr) {
92 try {
93 info.debuglevel_ = boost::lexical_cast<int>(debuglevel_ptr->str());
94 if ( (info.debuglevel_ < 0) || (info.debuglevel_ > 99) ) {
95 // Comment doesn't matter, it is caught several lines below
96 isc_throw(BadValue, "");
97 }
98 } catch (...) {
99 isc_throw(BadValue, "Unsupported debuglevel value "
100 << debuglevel_ptr->intValue()
101 << ", expected 0-99 ("
102 << debuglevel_ptr->getPosition() << ")");
103 }
104 }
105
106 // We want to follow the normal path, so it could catch parsing errors even
107 // when verbose mode is enabled. If it is, just override whatever was parsed
108 // in the config file.
109 if (verbose_) {
110 info.severity_ = isc::log::DEBUG;
111 info.debuglevel_ = 99;
112 }
113
114 isc::data::ConstElementPtr output_options = entry->get("output-options");
115 isc::data::ConstElementPtr deprecated_output_options = entry->get("output_options");
116
117 if (output_options && deprecated_output_options) {
118 isc_throw(BadValue, "Only one of 'output-options' and 'output_options' may be specified.");
119 }
120
121 if (deprecated_output_options) {
123 output_options = deprecated_output_options;
124 ElementPtr mutable_element = boost::const_pointer_cast<Element>(entry);
125 mutable_element->remove("output_options");
126 mutable_element->set("output-options", output_options);
127 }
128
129 if (output_options) {
130 parseOutputOptions(info.destinations_, output_options);
131 }
132
133 config_->addLoggingInfo(info);
134}
135
136std::string
137LogConfigParser::getLogPath(bool reset /* = false */, const std::string explicit_path /* = "" */) {
138 if (!log_path_checker_ || reset) {
139 log_path_checker_.reset(new PathChecker(LOGFILE_DIR, "KEA_LOG_FILE_DIR"));
140 if (!explicit_path.empty()) {
141 log_path_checker_->getPath(true, explicit_path);
142 }
143 }
144
145 return (log_path_checker_->getPath());
146}
147
148std::string
149LogConfigParser::validatePath(const std::string logpath) {
150 if (!log_path_checker_) {
151 getLogPath();
152 }
153
154 try {
155 return (log_path_checker_->validatePath(logpath));
156 } catch (const SecurityWarn& ex) {
158 .arg(ex.what());
159 return (logpath);
160 }
161}
162
163void LogConfigParser::parseOutputOptions(std::vector<LoggingDestination>& destination,
164 isc::data::ConstElementPtr output_options) {
165 if (!output_options) {
166 isc_throw(BadValue, "Missing 'output-options' structure in 'loggers'");
167 }
168
169 for (auto const& output_option : output_options->listValue()) {
170
171 LoggingDestination dest;
172
173 isc::data::ConstElementPtr output = output_option->get("output");
174 if (!output) {
175 isc_throw(BadValue, "output-options entry does not have a mandatory 'output' "
176 "element (" << output_option->getPosition() << ")");
177 }
178
179 auto output_str = output->stringValue();
180 if ((output_str == "stdout") ||
181 (output_str == "stderr") ||
182 (output_str == "syslog") ||
183 (output_str.find("syslog:") == 0)) {
184 dest.output_ = output_str;
185 } else {
186 try {
187 dest.output_ = validatePath(output_str);
188 } catch (const std::exception& ex) {
189 isc_throw(BadValue, "invalid path in `output`: " << ex.what()
190 << " (" << output_option->getPosition() << ")");
191 }
192 }
193
194 isc::data::ConstElementPtr maxver_ptr = output_option->get("maxver");
195 if (maxver_ptr) {
196 dest.maxver_ = boost::lexical_cast<int>(maxver_ptr->str());
197 }
198
199 isc::data::ConstElementPtr maxsize_ptr = output_option->get("maxsize");
200 if (maxsize_ptr) {
201 dest.maxsize_ = boost::lexical_cast<uint64_t>(maxsize_ptr->str());
202 }
203
204 isc::data::ConstElementPtr flush_ptr = output_option->get("flush");
205 if (flush_ptr) {
206 dest.flush_ = flush_ptr->boolValue();
207 }
208
209 isc::data::ConstElementPtr pattern = output_option->get("pattern");
210 if (pattern) {
211 dest.pattern_ = pattern->stringValue();
212 }
213
214 destination.push_back(dest);
215 }
216}
217
218} // namespace isc::dhcp
219} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
LogConfigParser(const ConfigPtr &storage)
Constructor.
Definition log_parser.cc:30
static std::string getLogPath(bool reset=false, const std::string explicit_path="")
Fetches the supported log file path.
static std::string validatePath(const std::string logpath)
Validates a library path against the supported path for log files.
void parseConfiguration(const isc::data::ConstElementPtr &log_config, bool verbose=false)
Parses specified configuration.
Definition log_parser.cc:38
Embodies a supported path against which file paths can be validated.
Definition filesystem.h:203
A generic exception that is thrown if a parameter given violates security check but enforcement is la...
Definition filesystem.h:21
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Logging initialization functions.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
@ info
Definition db_log.h:120
isc::log::Severity getSeverity(const std::string &sev_str)
Returns the isc::log::Severity value represented by the given string.
isc::log::Logger dctl_logger("dctl")
Defines the logger used within libkea-process library.
Definition d_log.h:18
boost::shared_ptr< ConfigBase > ConfigPtr
Non-const pointer to the ConfigBase.
const isc::log::MessageID DCTL_DEPRECATED_OUTPUT_OPTIONS
const isc::log::MessageID DCTL_LOG_PATH_SECURITY_WARNING
boost::shared_ptr< PathChecker > PathCheckerPtr
Defines a pointer to a PathChecker.
Definition filesystem.h:323
Defines the logger used by the top-level component of kea-lfc.