return token;
}
+bool
+ConfigParser::optionalKvPair(char * &key, char * &value)
+{
+ key = nullptr;
+ value = nullptr;
+
+ if (const char *currentToken = PeekAtToken()) {
+ // NextKvPair() accepts "a = b" and skips "=" or "a=". To avoid
+ // misinterpreting the admin intent, we use strict checks.
+ if (const auto middle = strchr(currentToken, '=')) {
+ if (middle == currentToken)
+ throw TextException(ToSBuf("missing key in a key=value option: ", currentToken), Here());
+ if (middle + 1 == currentToken + strlen(currentToken))
+ throw TextException(ToSBuf("missing value in a key=value option: ", currentToken), Here());
+ } else
+ return false; // not a key=value token
+
+ if (!NextKvPair(key, value)) // may still fail (e.g., bad value quoting)
+ throw TextException(ToSBuf("invalid key=value option: ", currentToken), Here());
+
+ return true;
+ }
+
+ return false; // end of directive or input
+}
+
bool
ConfigParser::NextKvPair(char * &key, char * &value)
{
/// rejects configuration due to a repeated directive
void rejectDuplicateDirective();
+ /// extracts an optional key=value token or returns false
+ /// rejects configurations with empty keys or empty values
+ /// key and value have lifetime of the current line/directive
+ bool optionalKvPair(char * &key, char * &value);
+
static void ParseUShort(unsigned short *var);
static void ParseBool(bool *var);
static const char *QuoteString(const String &var);
#include "auth/Config.h"
#include "auth/Scheme.h"
#include "AuthReg.h"
+#include "base/PackableStream.h"
#include "base/RunnersRegistry.h"
#include "cache_cf.h"
#include "CachePeer.h"
static int check_null_access_log(CustomLog *customlog_definitions);
static void dump_access_log(StoreEntry * entry, const char *name, CustomLog * definitions);
static void free_access_log(CustomLog ** definitions);
-static bool setLogformat(CustomLog *cl, const char *name, const bool dieWhenMissing);
static void configDoConfigure(void);
static void parse_refreshpattern(RefreshPattern **);
*
* #4: Configurable logging module with name=value options such as logformat=x:
* The first ACL name may not contain '='.
+ * Without any optional parts, directives using this style are indistinguishable
+ * from directives using style #1 until we start requiring the "module:" prefix.
* access_log module:place [option ...] [acl ...]
*
*/
return;
}
- CustomLog *cl = (CustomLog *)xcalloc(1, sizeof(*cl));
+ const auto cl = new CustomLog();
cl->filename = xstrdup(filename);
- // default buffer size and fatal settings
- cl->bufferSize = 8*MAX_URL;
- cl->fatal = true;
if (strcmp(filename, "none") == 0) {
cl->type = Log::Format::CLF_NONE;
return;
}
- cl->type = Log::Format::CLF_UNKNOWN;
- cl->rotateCount = -1; // default: use global logfile_rotate setting.
-
const char *token = ConfigParser::PeekAtToken();
- if (!token) { // style #1
- // no options to deal with
- } else if (!strchr(token, '=')) { // style #3
- // if logformat name is recognized,
- // pop the previewed token; Else it must be an ACL name
- if (setLogformat(cl, token, false))
- (void)ConfigParser::NextToken();
- } else { // style #4
- do {
- if (strncasecmp(token, "on-error=", 9) == 0) {
- if (strncasecmp(token+9, "die", 3) == 0) {
- cl->fatal = true;
- } else if (strncasecmp(token+9, "drop", 4) == 0) {
- cl->fatal = false;
- } else {
- debugs(3, DBG_CRITICAL, "Unknown value for on-error '" <<
- token << "' expected 'drop' or 'die'");
- xfree(cl->filename);
- xfree(cl);
- self_destruct();
- return;
- }
- } else if (strncasecmp(token, "buffer-size=", 12) == 0) {
- parseBytesOptionValue(&cl->bufferSize, B_BYTES_STR, token+12);
- } else if (strncasecmp(token, "rotate=", 7) == 0) {
- cl->rotateCount = xatoi(token + 7);
- } else if (strncasecmp(token, "logformat=", 10) == 0) {
- setLogformat(cl, token+10, true);
- } else if (!strchr(token, '=')) {
- // Do not pop the token; it must be an ACL name
- break; // done with name=value options, now to ACLs
- } else {
- debugs(3, DBG_CRITICAL, "Unknown access_log option " << token);
- xfree(cl->filename);
- xfree(cl);
- self_destruct();
- return;
- }
- // Pop the token, it was a valid "name=value" option
- (void)ConfigParser::NextToken();
- // Get next with preview ConfigParser::NextToken call.
- } while ((token = ConfigParser::PeekAtToken()) != NULL);
+ if (token && !strchr(token, '=')) { // style #3
+ // TODO: Deprecate this style to avoid this dangerous guessing.
+ if (Log::TheConfig.knownFormat(token)) {
+ cl->setLogformat(token);
+ (void)ConfigParser::NextToken(); // consume the token used above
+ } else {
+ // assume there is no explicit logformat name and use the default
+ cl->setLogformat("squid");
+ }
+ } else { // style #1 or style #4
+ // TODO: Drop deprecated style #1 support. We already warn about it, and
+ // its exceptional treatment makes detecting "module" typos impractical!
+ cl->parseOptions(LegacyParser, "squid");
}
-
- // set format if it has not been specified explicitly
- if (cl->type == Log::Format::CLF_UNKNOWN)
- setLogformat(cl, "squid", true);
+ assert(cl->type); // setLogformat() was called
aclParseAclList(LegacyParser, &cl->aclList, cl->filename);
*logs = cl;
}
-/// sets CustomLog::type and, if needed, CustomLog::lf
-/// returns false iff there is no named log format
-static bool
-setLogformat(CustomLog *cl, const char *logdef_name, const bool dieWhenMissing)
-{
- assert(cl);
- assert(logdef_name);
-
- debugs(3, 9, "possible " << cl->filename << " logformat: " << logdef_name);
-
- if (cl->type != Log::Format::CLF_UNKNOWN) {
- debugs(3, DBG_CRITICAL, "FATAL: Second logformat name in one access_log: " <<
- logdef_name << " " << cl->type << " ? " << Log::Format::CLF_NONE);
- self_destruct();
- return false;
- }
-
- /* look for the definition pointer corresponding to this name */
- Format::Format *lf = Log::TheConfig.logformats;
-
- while (lf != NULL) {
- debugs(3, 9, "Comparing against '" << lf->name << "'");
-
- if (strcmp(lf->name, logdef_name) == 0)
- break;
-
- lf = lf->next;
- }
-
- if (lf != NULL) {
- cl->type = Log::Format::CLF_CUSTOM;
- cl->logFormat = lf;
- } else if (strcmp(logdef_name, "auto") == 0) {
- debugs(0, DBG_CRITICAL, "WARNING: Log format 'auto' no longer exists. Using 'squid' instead.");
- cl->type = Log::Format::CLF_SQUID;
- } else if (strcmp(logdef_name, "squid") == 0) {
- cl->type = Log::Format::CLF_SQUID;
- } else if (strcmp(logdef_name, "common") == 0) {
- cl->type = Log::Format::CLF_COMMON;
- } else if (strcmp(logdef_name, "combined") == 0) {
- cl->type = Log::Format::CLF_COMBINED;
-#if ICAP_CLIENT
- } else if (strcmp(logdef_name, "icap_squid") == 0) {
- cl->type = Log::Format::CLF_ICAP_SQUID;
-#endif
- } else if (strcmp(logdef_name, "useragent") == 0) {
- cl->type = Log::Format::CLF_USERAGENT;
- } else if (strcmp(logdef_name, "referrer") == 0) {
- cl->type = Log::Format::CLF_REFERER;
- } else if (dieWhenMissing) {
- debugs(3, DBG_CRITICAL, "FATAL: Log format '" << logdef_name << "' is not defined");
- self_destruct();
- return false;
- } else {
- return false;
- }
-
- return true;
-}
-
static int
check_null_access_log(CustomLog *customlog_definitions)
{
static void
dump_access_log(StoreEntry * entry, const char *name, CustomLog * logs)
{
- CustomLog *log;
-
- for (log = logs; log; log = log->next) {
- storeAppendPrintf(entry, "%s ", name);
-
- switch (log->type) {
-
- case Log::Format::CLF_CUSTOM:
- storeAppendPrintf(entry, "%s logformat=%s", log->filename, log->logFormat->name);
- break;
-
- case Log::Format::CLF_NONE:
- storeAppendPrintf(entry, "logformat=none");
- break;
-
- case Log::Format::CLF_SQUID:
- // this is the default, no need to add to the dump
- //storeAppendPrintf(entry, "%s logformat=squid", log->filename);
- break;
-
- case Log::Format::CLF_COMBINED:
- storeAppendPrintf(entry, "%s logformat=combined", log->filename);
- break;
-
- case Log::Format::CLF_COMMON:
- storeAppendPrintf(entry, "%s logformat=common", log->filename);
- break;
-
-#if ICAP_CLIENT
- case Log::Format::CLF_ICAP_SQUID:
- storeAppendPrintf(entry, "%s logformat=icap_squid", log->filename);
- break;
-#endif
- case Log::Format::CLF_USERAGENT:
- storeAppendPrintf(entry, "%s logformat=useragent", log->filename);
- break;
-
- case Log::Format::CLF_REFERER:
- storeAppendPrintf(entry, "%s logformat=referrer", log->filename);
- break;
-
- case Log::Format::CLF_UNKNOWN:
- break;
+ assert(entry);
+ for (auto log = logs; log; log = log->next) {
+ {
+ PackableStream os(*entry);
+ os << name; // directive name
+ os << ' ' << log->filename; // including "none"
+ log->dumpOptions(os);
}
- // default is on-error=die
- if (!log->fatal)
- storeAppendPrintf(entry, " on-error=drop");
-
- // default: 64KB
- if (log->bufferSize != 64*1024)
- storeAppendPrintf(entry, " buffer-size=%" PRIuSIZE, log->bufferSize);
-
- if (log->rotateCount >= 0)
- storeAppendPrintf(entry, " rotate=%d", log->rotateCount);
-
if (log->aclList)
dump_acl_list(entry, log->aclList);
while (*definitions) {
CustomLog *log = *definitions;
*definitions = log->next;
-
- log->logFormat = NULL;
- log->type = Log::Format::CLF_UNKNOWN;
-
- if (log->aclList)
- aclDestroyAclList(&log->aclList);
-
- safe_free(log->filename);
-
- xfree(log);
+ delete log;
}
}
Log::LogConfig Log::TheConfig;
+const char *
+Log::LogConfig::BuiltInFormatName(const Format::log_type logformatType)
+{
+ switch (logformatType) {
+ case Format::CLF_UNKNOWN:
+ case Format::CLF_NONE:
+ case Format::CLF_CUSTOM:
+ return nullptr; // the above types are not built-in
+
+ case Format::CLF_SQUID:
+ return "squid";
+
+ case Format::CLF_COMBINED:
+ return "combined";
+
+ case Format::CLF_COMMON:
+ return "common";
+
+#if ICAP_CLIENT
+ case Format::CLF_ICAP_SQUID:
+ return "icap_squid";
+#endif
+
+ case Format::CLF_USERAGENT:
+ return "useragent";
+
+ case Log::Format::CLF_REFERER:
+ return "referrer";
+ }
+
+ // forgotten (by developers) type, invalid type, or unreachable code
+ return nullptr;
+}
+
+Log::Format::log_type
+Log::LogConfig::FindBuiltInFormat(const char *logformatName)
+{
+ assert(logformatName);
+
+ if (strcmp(logformatName, "auto") == 0) {
+ debugs(0, DBG_CRITICAL, "WARNING: Log format 'auto' no longer exists. Using 'squid' instead.");
+ return Format::CLF_SQUID;
+ }
+
+ if (strcmp(logformatName, "squid") == 0)
+ return Format::CLF_SQUID;
+
+ if (strcmp(logformatName, "common") == 0)
+ return Format::CLF_COMMON;
+
+ if (strcmp(logformatName, "combined") == 0)
+ return Format::CLF_COMBINED;
+
+#if ICAP_CLIENT
+ if (strcmp(logformatName, "icap_squid") == 0)
+ return Format::CLF_ICAP_SQUID;
+#endif
+
+ if (strcmp(logformatName, "useragent") == 0)
+ return Format::CLF_USERAGENT;
+
+ if (strcmp(logformatName, "referrer") == 0)
+ return Format::CLF_REFERER;
+
+ // CLF_NONE, CLF_UNKNOWN, CLF_CUSTOM types cannot be specified explicitly.
+ // TODO: Ban "none" and "unknown" custom logformat names to avoid confusion.
+ return Format::CLF_UNKNOWN;
+}
+
+Format::Format *
+Log::LogConfig::findCustomFormat(const char *logformatName) const
+{
+ assert(logformatName);
+ for (auto i = logformats; i ; i = i->next) {
+ if (strcmp(i->name, logformatName) == 0)
+ return i;
+ }
+ return nullptr;
+}
+
+bool
+Log::LogConfig::knownFormat(const char *logformatName) const
+{
+ return FindBuiltInFormat(logformatName) || findCustomFormat(logformatName);
+}
+
void
Log::LogConfig::parseFormats()
{
return;
}
- // check for re-definition of built-in formats
- if (strcmp(name, "squid") == 0 ||
- strcmp(name, "common") == 0 ||
- strcmp(name, "combined") == 0 ||
- strcmp(name, "useragent") == 0 ||
- strcmp(name, "referrer") == 0) {
- debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: logformat " << name << " is already defined. Ignoring.");
+ if (FindBuiltInFormat(name)) {
+ debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: logformat " << name << " is a built-in format. Ignoring redefinition attempt.");
return;
}
- // check for re-definition of custom formats
- for (auto i = logformats; i ; i = i->next) {
- if (strcmp(i->name, name) == 0) {
- debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: logformat " << name << " is already defined. Ignoring.");
- return;
- }
+ if (findCustomFormat(name)) {
+ debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: logformat " << name << " is already defined. Ignoring redefinition attempt.");
+ return;
}
::Format::Format *nlf = new ::Format::Format(name);
#define SQUID_SRC_LOG_CONFIG_H
#include "format/Format.h"
+#include "log/Formats.h"
class StoreEntry;
class LogConfig
{
public:
+ /// \returns the name of the given built-in logformat type (or nil)
+ static const char *BuiltInFormatName(Format::log_type type);
+
+ /// \returns either a named built-in logformat ID or CLF_UNKNOWN
+ static Format::log_type FindBuiltInFormat(const char *logformatName);
+ static_assert(!Log::Format::CLF_UNKNOWN, "FindBuiltInFormat(unknown) is falsy");
+
+ /// \returns a named (previously configured) custom log format object or nil
+ ::Format::Format *findCustomFormat(const char *logformatName) const;
+
+ /// whether the given format name is supported, either as a built-in or a
+ /// (previously configured) custom logformat
+ bool knownFormat(const char *logformatName) const;
+
void parseFormats();
void dumpFormats(StoreEntry *e, const char *name) {
logformats->dump(e, name);
+++ /dev/null
-/*
- * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#include "squid.h"
-#include "log/CustomLog.h"
-#include "log/File.h"
-
-bool
-CustomLog::usesDaemon() const
-{
- return (filename && strncmp(filename, "daemon:", 7) == 0);
-}
-
#ifndef SQUID_CUSTOMLOG_H_
#define SQUID_CUSTOMLOG_H_
-#include "acl/forward.h"
-#include "log/Formats.h"
+#include "log/FormattedLog.h"
-class Logfile;
-namespace Format
-{
-class Format;
-}
-
-/// representation of a custom log directive.
-class CustomLog
+// TODO: Replace with std::list<FormattedLog> or its wrapper.
+/// all same-directive transaction logging rules
+/// (e.g., all access_log rules or all icap_log rules)
+class CustomLog: public FormattedLog
{
public:
- /// \returns whether the daemon module is used for this log
- bool usesDaemon() const;
-
- char *filename;
- ACLList *aclList;
- Format::Format *logFormat;
- Logfile *logfile;
- CustomLog *next;
- Log::Format::log_type type;
- /// how much to buffer before dropping or dying (access_log buffer-size)
- size_t bufferSize;
- /// whether unrecoverable errors (e.g., dropping a log record) kill worker
- bool fatal;
- /// How many log files to retain when rotating. Default: obey logfile_rotate
- int16_t rotateCount;
+ /// next _log line (if any); maintained by cache_cf.cc
+ CustomLog *next = nullptr;
};
#endif /* SQUID_CUSTOMLOG_H_ */
--- /dev/null
+/*
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "acl/Gadgets.h"
+#include "base/TextException.h"
+#include "cache_cf.h"
+#include "Debug.h"
+#include "log/Config.h"
+#include "log/File.h"
+#include "log/FormattedLog.h"
+#include "Parsing.h"
+#include "sbuf/Stream.h"
+#include "SquidConfig.h"
+
+FormattedLog::~FormattedLog()
+{
+ close(); // TODO: destructing a Logfile object should be enough
+ aclDestroyAclList(&aclList);
+ safe_free(filename);
+ // leave logFormat alone -- we do not own that object
+}
+
+bool
+FormattedLog::usesDaemon() const
+{
+ return (filename && strncmp(filename, "daemon:", 7) == 0);
+}
+
+void
+FormattedLog::parseOptions(ConfigParser &parser, const char *defaultFormatName)
+{
+ const char *explicitFormatName = nullptr;
+ char *key = nullptr;
+ char *value = nullptr;
+ while (parser.optionalKvPair(key, value)) {
+
+ if (strcmp(key, "on-error") == 0) {
+ if (strcmp(value, "die") == 0) {
+ fatal = true;
+ } else if (strcmp(value, "drop") == 0) {
+ fatal = false;
+ } else {
+ throw TextException(ToSBuf("unsupported ", cfg_directive, " on-error value: ", value,
+ Debug::Extra, "expected 'drop' or 'die'"), Here());
+ }
+ continue;
+ }
+
+ if (strcmp(key, "buffer-size") == 0) {
+ parseBytesOptionValue(&bufferSize, "bytes", value);
+ continue;
+ }
+
+ if (strcmp(key, "rotate") == 0) {
+ rotationsToKeep = Optional<unsigned int>(xatoui(value));
+ continue;
+ }
+
+ if (strcmp(key, "logformat") == 0 && defaultFormatName) {
+ if (explicitFormatName)
+ throw TextException(ToSBuf("duplicated ", cfg_directive, " option: ", key), Here());
+
+ explicitFormatName = value;
+ continue;
+ }
+
+ throw TextException(ToSBuf("unsupported ", cfg_directive, " option: ", key, "=", value), Here());
+ }
+
+ if (const auto formatName = explicitFormatName ? explicitFormatName : defaultFormatName) {
+ assert(defaultFormatName); // this log supports logformat=name
+ setLogformat(formatName);
+ } // else OK: this log does not support logformat=name and none was given
+}
+
+void
+FormattedLog::dumpOptions(std::ostream &os) const
+{
+ /* do not report defaults */
+
+ // TODO: Here and elsewhere, report both explicitly configured settings and
+ // various defaults. Properly excluding defaults requires wrapping most
+ // non-pointer members in Optional _and_ adding methods to compute the final
+ // option value after accounting for defaults (and those may change with
+ // reconfiguration!). And all that effort may still not result in a faithful
+ // reproduction of the original squid.conf because of size unit changes,
+ // order changes, duplicates removal, etc. More importantly, these reports
+ // are much more useful for determining complete Squid state (especially
+ // when triaging older Squids with some difficult-to-figure-out defaults).
+
+ switch (type) {
+ case Log::Format::CLF_UNKNOWN:
+ break; // do not report a format when it was not configured
+
+ case Log::Format::CLF_NONE:
+ break; // the special "none" case has no format to report
+
+ case Log::Format::CLF_SQUID:
+ break; // do not report default format (XXX: icap_log default differs)
+
+ case Log::Format::CLF_CUSTOM:
+ if (logFormat) // paranoid; the format should be set
+ os << " logformat=" << logFormat->name;
+ break;
+
+ default:
+ os << " logformat=" << Log::LogConfig::BuiltInFormatName(type);
+ }
+
+ if (!fatal)
+ os << " on-error=drop";
+
+ if (bufferSize != 8*MAX_URL)
+ os << " buffer-size=" << bufferSize << "bytes";
+
+ if (rotationsToKeep)
+ os << " rotate=" << rotationsToKeep.value();
+}
+
+void
+FormattedLog::setLogformat(const char *logformatName)
+{
+ assert(logformatName);
+ assert(type == Log::Format::CLF_UNKNOWN); // set only once
+ assert(!logFormat); // set only once
+
+ debugs(3, 7, "possible " << filename << " logformat: " << logformatName);
+
+ if (const auto lf = Log::TheConfig.findCustomFormat(logformatName)) {
+ type = Log::Format::CLF_CUSTOM;
+ logFormat = lf;
+ return;
+ }
+
+ if (const auto id = Log::LogConfig::FindBuiltInFormat(logformatName)) {
+ type = id;
+ return;
+ }
+
+ throw TextException(ToSBuf("unknown logformat name in ", cfg_directive, ": ", logformatName), Here());
+}
+
+void
+FormattedLog::open()
+{
+ Must(!logfile);
+ Must(filename);
+ logfile = logfileOpen(filename, bufferSize, fatal);
+ // the opening code reports failures and returns nil if they are non-fatal
+}
+
+void
+FormattedLog::rotate()
+{
+ if (logfile)
+ logfileRotate(logfile, rotationsToKeep.value_or(Config.Log.rotateNumber));
+}
+
+void
+FormattedLog::close()
+{
+ if (logfile) {
+ logfileClose(logfile);
+ logfile = nullptr; // deleted by the closing code
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_LOG_FORMATTEDLOG_H_
+#define SQUID_LOG_FORMATTEDLOG_H_
+
+#include "acl/forward.h"
+#include "base/Optional.h"
+#include "log/Formats.h"
+#include "log/forward.h"
+
+#include <iosfwd>
+
+class ConfigParser;
+
+/// A single-destination, single-record-format log.
+/// The customizable destination is based on Logfile "logging modules" API.
+/// Some logs allow the admin to select or specify the record format.
+class FormattedLog
+{
+public:
+ FormattedLog() = default;
+ ~FormattedLog();
+
+ FormattedLog(FormattedLog &&) = delete; // no need to support copying of any kind
+
+ /// \returns whether the daemon module is used for this log
+ bool usesDaemon() const;
+
+ /// handles the [key=value...] part of the log configuration
+ /// \param defaultFormat default logformat or, to force built-in format, nil
+ void parseOptions(ConfigParser&, const char *defaultFormat);
+
+ /// reports explicitly-configured key=value options, in squid.conf format
+ void dumpOptions(std::ostream &os) const;
+
+ /// configures formatting-related settings for the given logformat name
+ void setLogformat(const char *logformatName);
+
+ /// prepare for recording entries
+ void open();
+
+ /// handle the log rotation request
+ void rotate();
+
+ /// stop recording entries
+ void close();
+
+ /// records writer
+ Logfile *logfile = nullptr;
+
+ /// logging destination
+ char *filename = nullptr;
+
+ /// restrict logging to matching transactions
+ ACLList *aclList = nullptr;
+
+ /// custom log record template for type == Log::Format::CLF_CUSTOM
+ Format::Format *logFormat = nullptr;
+
+ /// log record template ID
+ Log::Format::log_type type = Log::Format::CLF_UNKNOWN;
+
+ /// how much to buffer before dropping or dying (buffer-size=N)
+ size_t bufferSize = 8*MAX_URL;
+
+ /// how many log files to retain when rotating. Default: obey logfile_rotate
+ Optional<unsigned int> rotationsToKeep;
+
+ /// whether unrecoverable errors (e.g., dropping a log record) kill worker
+ bool fatal = true;
+};
+
+#endif /* SQUID_LOG_FORMATTEDLOG_H_ */
+
liblog_la_SOURCES = \
Config.cc \
Config.h \
- CustomLog.cc \
CustomLog.h \
File.cc \
File.h \
FormatSquidReferer.cc \
FormatSquidUseragent.cc \
Formats.h \
+ FormattedLog.cc \
+ FormattedLog.h \
ModDaemon.cc \
ModDaemon.h \
ModStdio.cc \
#endif
for (log = Config.Log.accesslogs; log; log = log->next) {
- if (log->logfile) {
- int16_t rc = (log->rotateCount >= 0 ? log->rotateCount : Config.Log.rotateNumber);
- logfileRotate(log->logfile, rc);
- }
+ log->rotate();
}
#if HEADERS_LOG
class AccessLogEntry;
typedef RefCount<AccessLogEntry> AccessLogEntryPointer;
+class Logfile;
class LogTags;
class LogTagsErrors;
void parse_time_t(time_t * var) STUB
void ConfigParser::ParseUShort(unsigned short *var) STUB
void ConfigParser::ParseWordList(wordlist **) STUB
+void parseBytesOptionValue(size_t *, const char *, char const * value) STUB
void dump_acl_access(StoreEntry * entry, const char *name, acl_access * head) STUB
void dump_acl_list(StoreEntry*, ACLList*) STUB
LogConfig TheConfig;
}
-#include "log/CustomLog.h"
-bool CustomLog::usesDaemon() const STUB_RETVAL(false)
+#include "log/FormattedLog.h"
+bool FormattedLog::usesDaemon() const STUB_RETVAL(false)
#include "log/File.h"
CBDATA_CLASS_INIT(Logfile);