]> git.ipfire.org Git - thirdparty/squid.git/blob - src/log/FormattedLog.cc
fcb5b0221f881409bac2b61e836de84f0f47baa7
[thirdparty/squid.git] / src / log / FormattedLog.cc
1 /*
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
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"
13 #include "debug/Stream.h"
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
21 FormattedLog::~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
29 bool
30 FormattedLog::usesDaemon() const
31 {
32 return (filename && strncmp(filename, "daemon:", 7) == 0);
33 }
34
35 void
36 FormattedLog::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) {
61 rotationsToKeep = std::optional<unsigned int>(xatoui(value));
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
82 void
83 FormattedLog::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
89 // non-pointer members in std::optional and adding methods to compute the final
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
126 void
127 FormattedLog::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
149 void
150 FormattedLog::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
158 void
159 FormattedLog::rotate()
160 {
161 if (logfile)
162 logfileRotate(logfile, rotationsToKeep.value_or(Config.Log.rotateNumber));
163 }
164
165 void
166 FormattedLog::close()
167 {
168 if (logfile) {
169 logfileClose(logfile);
170 logfile = nullptr; // deleted by the closing code
171 }
172 }
173