Skip to content

Commit

Permalink
Unify the logging config so that JSON logging works (#456)
Browse files Browse the repository at this point in the history
* Unify the logging config so that JSON logging works

* Release v1.0.8
  • Loading branch information
mmwinther authored Dec 3, 2024
1 parent 0035b5d commit a56201c
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 122 deletions.
35 changes: 2 additions & 33 deletions gunicorn.conf.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,9 @@
"""Configuration for the Gunicorn server."""

import sys
from datadoc.logging_configuration.logging_config import get_log_config

bind = "0.0.0.0:8050"
workers = 1
loglevel = "info"
preload = True

logconfig_dict = GUNICORN_LOG_CONFIG = {
"handlers": {
"console_stdout": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"stream": sys.stdout,
},
},
"loggers": {
"": {"handlers": ["console_stdout"], "level": "INFO", "propagate": False},
"gunicorn": {
"handlers": ["console_stdout"],
"level": "INFO",
"propagate": False,
},
"gunicorn.access": {
"handlers": ["console_stdout"],
"level": "INFO",
"propagate": False,
},
"gunicorn.error": {
"handlers": ["console_stdout"],
"level": "INFO",
"propagate": False,
},
},
"root": {
"level": "INFO",
"handlers": ["console_stdout"],
},
}
logconfig_dict = get_log_config()
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "ssb-datadoc"
version = "1.0.7"
version = "1.0.8"
description = "Document dataset metadata. For use in Statistics Norway's metadata system."
authors = ["Statistics Norway <[email protected]>"]
license = "MIT"
Expand Down Expand Up @@ -161,6 +161,9 @@ max-complexity = 15
[tool.ruff.lint.pydocstyle]
convention = "google" # You can also use "numpy".

[tool.ruff.lint.flake8-pytest-style]
fixture-parentheses = false

[tool.ruff.lint.pep8-naming]
classmethod-decorators = [
"classmethod",
Expand Down
4 changes: 2 additions & 2 deletions src/datadoc/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
from datadoc.frontend.components.control_bars import build_controls_bar
from datadoc.frontend.components.control_bars import build_footer_control_bar
from datadoc.frontend.components.control_bars import header
from datadoc.logging_configuration.logging_config import configure_logging
from datadoc.logging_configuration.logging_config import get_log_config
from datadoc.utils import get_app_version
from datadoc.utils import pick_random_port
from datadoc.utils import running_in_notebook

configure_logging()
logging.config.dictConfig(get_log_config())
logger = logging.getLogger(__name__)


Expand Down
16 changes: 1 addition & 15 deletions src/datadoc/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,16 @@

from __future__ import annotations

import logging
import os
import sys
from pathlib import Path
from pprint import pformat
from typing import Literal

from dapla_metadata.datasets import enums
from dotenv import dotenv_values
from dotenv import load_dotenv

from datadoc.constants import DAPLA_MANUAL_TEXT
from datadoc.frontend.components.builders import build_link_object

logging.basicConfig(level=logging.DEBUG, force=True, stream=sys.stdout)

logger = logging.getLogger(__name__)

DOT_ENV_FILE_PATH = Path(__file__).parent.joinpath(".env")

JUPYTERHUB_USER = "JUPYTERHUB_USER"
Expand All @@ -34,18 +26,12 @@ def _load_dotenv_file() -> None:
if not env_loaded and DOT_ENV_FILE_PATH.exists():
load_dotenv(DOT_ENV_FILE_PATH)
env_loaded = True
logger.info(
"Loaded .env file with config keys: \n%s",
pformat(list(dotenv_values(DOT_ENV_FILE_PATH).keys())),
)


def _get_config_item(item: str) -> str | None:
"""Get a config item. Makes sure all access is logged."""
_load_dotenv_file()
value = os.getenv(item)
logger.debug("Config accessed. %s", item)
return value
return os.getenv(item)


def get_jupyterhub_user() -> str | None:
Expand Down
11 changes: 11 additions & 0 deletions src/datadoc/logging_configuration/gunicorn_access_log_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import logging

EXCLUDED_PATHS = ["/healthz", "/_dash-", "/assets"]


class GunicornAccessLoggerHealthProbeFilter(logging.Filter):
"""Filter out any Gunicorn access logs on Liveness or Readiness probes."""

def filter(self, record: logging.LogRecord) -> bool:
"""Filter health probes on the /healthz endpoints."""
return all(path not in record.getMessage() for path in EXCLUDED_PATHS)
96 changes: 55 additions & 41 deletions src/datadoc/logging_configuration/logging_config.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,69 @@
from __future__ import annotations

import logging.config
from typing import Any

from datadoc.config import get_log_formatter
from datadoc.config import get_log_level
from datadoc.logging_configuration.gunicorn_access_log_filter import (
GunicornAccessLoggerHealthProbeFilter,
)


def configure_logging(config: dict[str, Any] | None = None) -> None:
def get_log_config() -> dict[str, Any]:
"""Configure logging for the application."""
if not config:
config = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"simple": {
"format": "%(asctime)s.%(msecs)03d %(levelname)s %(name)s: %(message)s",
return {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"simple": {
"format": "%(asctime)s.%(msecs)03d %(levelname)s %(name)s: %(message)s",
"logger": "name",
"datefmt": "%Y-%m-%d %H:%M:%S",
},
"json": {
"()": "datadoc.logging_configuration.json_formatter.DatadocJSONFormatter",
"fmt_keys": {
"level": "levelname",
"message": "message",
"timestamp": "timestamp",
"logger": "name",
"datefmt": "%Y-%m-%d %H:%M:%S",
},
"json": {
"()": "datadoc.logging_configuration.json_formatter.DatadocJSONFormatter",
"fmt_keys": {
"level": "levelname",
"message": "message",
"timestamp": "timestamp",
"logger": "name",
"module": "module",
"function": "funcName",
"line": "lineno",
"thread_name": "threadName",
},
"module": "module",
"function": "funcName",
"line": "lineno",
"thread_name": "threadName",
},
},
"handlers": {
"stdout": {
"class": "logging.StreamHandler",
"level": get_log_level(),
"formatter": get_log_formatter(),
"stream": "ext://sys.stdout",
},
},
"handlers": {
"stdout": {
"class": "logging.StreamHandler",
"level": get_log_level(),
"formatter": get_log_formatter(),
"stream": "ext://sys.stdout",
},
"loggers": {
"root": {
"level": get_log_level(),
"handlers": [
"stdout",
],
},
},
"loggers": {
"gunicorn": {
"handlers": ["stdout"],
"level": "INFO",
"propagate": False,
},
}

logging.config.dictConfig(config)
logging.getLogger("faker").setLevel(logging.ERROR)
"gunicorn.access": {
"handlers": ["stdout"],
"level": "INFO",
"propagate": False,
"filters": [GunicornAccessLoggerHealthProbeFilter()],
},
"gunicorn.error": {
"handlers": ["stdout"],
"level": "INFO",
"propagate": False,
},
},
"root": {
"level": get_log_level(),
"handlers": [
"stdout",
],
},
}
Loading

0 comments on commit a56201c

Please sign in to comment.