Skip to content

Commit

Permalink
tools: add logfmt option for frr-reload.py
Browse files Browse the repository at this point in the history
Add the option of printing logs in logfmt format.

Additional machine readable information can be printed via the `extra`
argument.
Example:
```python
log.debug("exit context"), extra={"line": line, "ctx_keys": ctx_keys})

log.error(f"Failed to execute command {' '.join(cmd)}", extra={"cmd": cmd})
```

Signed-off-by: Giovanni Tataranni <[email protected]>
  • Loading branch information
gtataranni committed Jan 13, 2025
1 parent a09e949 commit 7ae71ae
Showing 1 changed file with 64 additions and 14 deletions.
78 changes: 64 additions & 14 deletions tools/frr-reload.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from __future__ import print_function, unicode_literals
import argparse
import datetime
import logging
import os, os.path
import random
Expand Down Expand Up @@ -1978,6 +1979,51 @@ def compare_context_objects(newconf, running):
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'
record.msg = record.getMessage().replace('"', '\\"')
record.msg = record.msg.replace("\n", "\\n")
# Format the time in RFC 3339 format
timestamp = datetime.datetime.fromtimestamp(
record.created, datetime.timezone.utc
)
record.asctime = timestamp.astimezone().isoformat(timespec="seconds")
# Create logfmt style log message, ignore default fields
logfmt = f'ts={record.asctime} level={record.levelname} msg="{record.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(
Expand Down Expand Up @@ -2045,36 +2091,40 @@ def compare_context_objects(newconf, running):
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)
Expand Down

0 comments on commit 7ae71ae

Please sign in to comment.