from __future__ import print_function, unicode_literals
import argparse
+import datetime
import logging
import os, os.path
import random
return (lines_to_add, lines_to_del)
+class LogFmtFormatter(logging.Formatter):
+ def format(self, record: logging.LogRecord) -> str:
+ """
+ Creates log messages with key=value pairs, in logfmt format.
+ """
+ # Escape double quotes in the message, replace newlines with '\n'
+ msg = record.getMessage().replace('"', '\\"').replace("\n", "\\n").strip()
+ # Format the time in RFC 3339 format
+ timestamp = datetime.datetime.fromtimestamp(
+ record.created, datetime.timezone.utc
+ )
+ asctime = timestamp.astimezone().isoformat(timespec="seconds")
+ # Create logfmt style log message, ignore default fields
+ logfmt = f'ts={asctime} level={record.levelname} msg="{msg}"'
+ default_fields = [
+ "args",
+ "asctime",
+ "created",
+ "exc_info",
+ "exc_text",
+ "filename",
+ "funcName",
+ "levelname",
+ "levelno",
+ "lineno",
+ "module",
+ "msecs",
+ "msg",
+ "name",
+ "pathname",
+ "process",
+ "processName",
+ "relativeCreated",
+ "stack_info",
+ "thread",
+ "threadName",
+ ]
+ for key, value in vars(record).items():
+ if key in default_fields:
+ continue
+ logfmt += f" {key}={value}"
+ return logfmt
+
+
if __name__ == "__main__":
# Command line options
parser = argparse.ArgumentParser(
action="store_true",
help="Used by topotest to not delete debug or log file commands",
)
+ parser.add_argument(
+ "--logfmt",
+ action="store_true",
+ help="Use logfmt as log format",
+ default=False,
+ )
args = parser.parse_args()
# Logging
# For --test log to stdout
# For --reload log to /var/log/frr/frr-reload.log
- if args.test or args.stdout:
- logging.basicConfig(format="%(asctime)s %(levelname)5s: %(message)s")
-
+ # If --logfmt, use the logfmt format
+ formatter = logging.Formatter("%(asctime)s %(levelname)5s: %(message)s")
+ handler = logging.StreamHandler()
+ if args.logfmt:
+ formatter = LogFmtFormatter()
+ elif args.test or args.stdout:
# Color the errors and warnings in red
logging.addLevelName(
logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR)
logging.addLevelName(
logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING)
)
-
- elif args.reload:
+ if args.reload:
if not os.path.isdir("/var/log/frr/"):
os.makedirs("/var/log/frr/", mode=0o0755)
-
- logging.basicConfig(
- filename="/var/log/frr/frr-reload.log",
- format="%(asctime)s %(levelname)5s: %(message)s",
- )
-
- # argparse should prevent this from happening but just to be safe...
- else:
- raise Exception("Must specify --reload or --test")
+ handler = logging.FileHandler("/var/log/frr/frr-reload.log")
+ if args.stdout:
+ handler = logging.StreamHandler(sys.stdout)
+ handler.setFormatter(formatter)
log = logging.getLogger(__name__)
+ log.addHandler(handler)
if args.debug:
log.setLevel(logging.DEBUG)