]> git.ipfire.org Git - thirdparty/squid.git/blame - src/log/FormattedLog.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / log / FormattedLog.cc
CommitLineData
39d7714a 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
39d7714a
AR
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9#include "squid.h"
10#include "acl/Gadgets.h"
11#include "base/TextException.h"
12#include "cache_cf.h"
675b8408 13#include "debug/Stream.h"
39d7714a
AR
14#include "log/Config.h"
15#include "log/File.h"
16#include "log/FormattedLog.h"
17#include "Parsing.h"
18#include "sbuf/Stream.h"
19#include "SquidConfig.h"
20
21FormattedLog::~FormattedLog()
22{
23 close(); // TODO: destructing a Logfile object should be enough
24 aclDestroyAclList(&aclList);
25 safe_free(filename);
26 // leave logFormat alone -- we do not own that object
27}
28
29bool
30FormattedLog::usesDaemon() const
31{
32 return (filename && strncmp(filename, "daemon:", 7) == 0);
33}
34
35void
36FormattedLog::parseOptions(ConfigParser &parser, const char *defaultFormatName)
37{
38 const char *explicitFormatName = nullptr;
39 char *key = nullptr;
40 char *value = nullptr;
41 while (parser.optionalKvPair(key, value)) {
42
43 if (strcmp(key, "on-error") == 0) {
44 if (strcmp(value, "die") == 0) {
45 fatal = true;
46 } else if (strcmp(value, "drop") == 0) {
47 fatal = false;
48 } else {
49 throw TextException(ToSBuf("unsupported ", cfg_directive, " on-error value: ", value,
50 Debug::Extra, "expected 'drop' or 'die'"), Here());
51 }
52 continue;
53 }
54
55 if (strcmp(key, "buffer-size") == 0) {
56 parseBytesOptionValue(&bufferSize, "bytes", value);
57 continue;
58 }
59
60 if (strcmp(key, "rotate") == 0) {
09835feb 61 rotationsToKeep = std::optional<unsigned int>(xatoui(value));
39d7714a
AR
62 continue;
63 }
64
65 if (strcmp(key, "logformat") == 0 && defaultFormatName) {
66 if (explicitFormatName)
67 throw TextException(ToSBuf("duplicated ", cfg_directive, " option: ", key), Here());
68
69 explicitFormatName = value;
70 continue;
71 }
72
73 throw TextException(ToSBuf("unsupported ", cfg_directive, " option: ", key, "=", value), Here());
74 }
75
76 if (const auto formatName = explicitFormatName ? explicitFormatName : defaultFormatName) {
77 assert(defaultFormatName); // this log supports logformat=name
78 setLogformat(formatName);
79 } // else OK: this log does not support logformat=name and none was given
80}
81
82void
83FormattedLog::dumpOptions(std::ostream &os) const
84{
85 /* do not report defaults */
86
87 // TODO: Here and elsewhere, report both explicitly configured settings and
88 // various defaults. Properly excluding defaults requires wrapping most
09835feb 89 // non-pointer members in std::optional and adding methods to compute the final
39d7714a
AR
90 // option value after accounting for defaults (and those may change with
91 // reconfiguration!). And all that effort may still not result in a faithful
92 // reproduction of the original squid.conf because of size unit changes,
93 // order changes, duplicates removal, etc. More importantly, these reports
94 // are much more useful for determining complete Squid state (especially
95 // when triaging older Squids with some difficult-to-figure-out defaults).
96
97 switch (type) {
98 case Log::Format::CLF_UNKNOWN:
99 break; // do not report a format when it was not configured
100
101 case Log::Format::CLF_NONE:
102 break; // the special "none" case has no format to report
103
104 case Log::Format::CLF_SQUID:
105 break; // do not report default format (XXX: icap_log default differs)
106
107 case Log::Format::CLF_CUSTOM:
108 if (logFormat) // paranoid; the format should be set
109 os << " logformat=" << logFormat->name;
110 break;
111
112 default:
113 os << " logformat=" << Log::LogConfig::BuiltInFormatName(type);
114 }
115
116 if (!fatal)
117 os << " on-error=drop";
118
119 if (bufferSize != 8*MAX_URL)
120 os << " buffer-size=" << bufferSize << "bytes";
121
122 if (rotationsToKeep)
123 os << " rotate=" << rotationsToKeep.value();
124}
125
126void
127FormattedLog::setLogformat(const char *logformatName)
128{
129 assert(logformatName);
130 assert(type == Log::Format::CLF_UNKNOWN); // set only once
131 assert(!logFormat); // set only once
132
133 debugs(3, 7, "possible " << filename << " logformat: " << logformatName);
134
135 if (const auto lf = Log::TheConfig.findCustomFormat(logformatName)) {
136 type = Log::Format::CLF_CUSTOM;
137 logFormat = lf;
138 return;
139 }
140
141 if (const auto id = Log::LogConfig::FindBuiltInFormat(logformatName)) {
142 type = id;
143 return;
144 }
145
146 throw TextException(ToSBuf("unknown logformat name in ", cfg_directive, ": ", logformatName), Here());
147}
148
149void
150FormattedLog::open()
151{
152 Must(!logfile);
153 Must(filename);
154 logfile = logfileOpen(filename, bufferSize, fatal);
155 // the opening code reports failures and returns nil if they are non-fatal
156}
157
158void
159FormattedLog::rotate()
160{
161 if (logfile)
162 logfileRotate(logfile, rotationsToKeep.value_or(Config.Log.rotateNumber));
163}
164
165void
166FormattedLog::close()
167{
168 if (logfile) {
169 logfileClose(logfile);
170 logfile = nullptr; // deleted by the closing code
171 }
172}
173