Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Introduce experimental JSON logging #16

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

lizard-boy
Copy link

Motivation

We've had a few requests in the past for outputting our logs in a structured format. We've been experimenting in the past but would like to push forward with the idea now. This will be in an experimental stage for some time now and will mostly be used internally before going into public preview and ideally GA release with 4.0 🤞

Changes

  • Logs can now also be streamed to a file in JSON format. This is done in a quite naive way right now, we simply take the current log records, and translate it into a JSON dict which then ends up being streamed as newline-delimited JSON where each line corresponds to one log entry.
  • The current CLI output is generally not affected by this (except by the addition of the raw request logger)

TODO

What's left to do:

  • Clean up the code from the initial spike
  • Make this opt-in
  • Make log sink configurable
  • Map keys extracted from the LogRecord to more suitable names
  • Investigate the DEBUG-related code we had to comment out for the aws request/response logging

There will also be some follow ups such as:

  • Add an internal endpoint to stream logs from (e.g. via websocket)
  • Introduce a proper structured logging strategy and rework log levels
  • ... lots more to come in the next few months

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This PR introduces experimental JSON logging to LocalStack, focusing on structured log output for improved analysis and debugging.

  • Added JsonFormatter class in localstack/logging/setup.py for JSON-formatted logs
  • Implemented new RequestLogger in localstack/aws/handlers/logging.py for raw HTTP request logging
  • Modified setup_logging function to include JSON logging configuration
  • Added log_request handler to the request chain in localstack/aws/app.py
  • Enhanced log messages with additional fields like request_id, service, and operation

5 file(s) reviewed, 7 comment(s)
Edit PR Review Bot Settings

@@ -45,3 +45,4 @@
set_close_connection_header = legacy.set_close_connection_header
push_request_context = legacy.push_request_context
pop_request_context = legacy.pop_request_context
log_request = logging.RequestLogger()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider adding a comment explaining the purpose of this new logger

Comment on lines 73 to 80
def _prepare_logger(self, logger: logging.Logger, formatter: Type):
if logger.isEnabledFor(logging.DEBUG):
logger.propagate = False
handler = create_default_handler(logger.level)
handler.setFormatter(formatter())
logger.addHandler(handler)
# TODO: uncommenting this will block .http and .aws logs from being propagated
# if logger.isEnabledFor(logging.DEBUG):
# logger.propagate = False
# handler = create_default_handler(logger.level)
# handler.setFormatter(formatter())
# logger.addHandler(handler)
return logger
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Commented-out code block prevents propagation of .http and .aws logs. Consider removing or implementing a configuration option to control this behavior.

Comment on lines +170 to +172
if context.request.path == "/health" or context.request.path == "/_localstack/health":
# special case so the health check doesn't spam the logs
return
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Duplicate health check logic. Consider extracting this into a separate method to avoid repetition.

@@ -87,6 +90,32 @@ def create_default_handler(log_level: int):
return log_handler


class JsonFormatter(logging.Formatter):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: JsonFormatter implementation is naive and may not handle all data types correctly. Consider using a more robust JSON serialization method.

Comment on lines +111 to +115
# import re
# reg = re.compile(r"./localstack/services/([^/])")
# if "localstack/services/" in record.pathname:
# service = record.pathname.split("")
# data["service"] =
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Commented-out code for service extraction. Either implement or remove this block.

Comment on lines +142 to +144
# TODO: make configurable/opt-in
logging.basicConfig(level=logging.DEBUG)
file_handler = logging.FileHandler("/tmp/localstack.log", mode="w", encoding="utf-8")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: JSON logging is not configurable and uses a hardcoded file path. Make this configurable as mentioned in the TODO.


file_handler.setFormatter(JsonFormatter())
logging.root.addHandler(file_handler)
logging.root.setLevel(logging.DEBUG) # FIXME
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Setting root logger to DEBUG level may be too verbose. Implement proper log level configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants