Skip to content

Commit c926420

Browse files
authored
chore: Improve logging setup (#873)
Introduces a logging setup to centralize its configuration and removes changes to the logging config from other places in the code base. The logging config is called in the bases __init__ file to be as early as possible applied. For sanic applications, it must also run for workers and the main process. The configuration sets up logging by default as follows: - our code is logged at level INFO - all third-party code is logged at level WARNING What is "our" code is determined by the logger name: our loggers should all be children of the renku_data_services logger. Using the provided getLogger function makes sure this is the case. The config can be adjusted using environment variables, as written in `Config.from_env()`.
1 parent e7ed6e3 commit c926420

52 files changed

Lines changed: 683 additions & 128 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
"""Renku data service."""
2+
3+
import renku_data_services.app_config.logging as logging
4+
5+
logging.configure_logging()

bases/renku_data_services/data_api/main.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
import sentry_sdk
99
import uvloop
1010
from sanic import Request, Sanic
11-
from sanic.log import logger
1211
from sanic.response import BaseHTTPResponse
1312
from sanic.worker.loader import AppLoader
1413
from sentry_sdk.integrations.asyncio import AsyncioIntegration
1514
from sentry_sdk.integrations.grpc import GRPCIntegration
1615
from sentry_sdk.integrations.sanic import SanicIntegration, _context_enter, _context_exit, _set_transaction
1716

1817
import renku_data_services.solr.entity_schema as entity_schema
18+
from renku_data_services.app_config.logging import configure_logging, getLogger
1919
from renku_data_services.authz.admin_sync import sync_admins_from_keycloak
2020
from renku_data_services.base_models.core import APIUser
2121
from renku_data_services.data_api.app import register_all_handlers
@@ -36,6 +36,9 @@
3636
import sentry_sdk._types
3737

3838

39+
logger = getLogger(__name__)
40+
41+
3942
async def _solr_reindex(app: Sanic) -> None:
4043
"""Run a solr reindex of all data.
4144
@@ -60,7 +63,7 @@ def solr_reindex(app_name: str) -> None:
6063
def create_app() -> Sanic:
6164
"""Create a Sanic application."""
6265
dependency_manager = DependencyManager.from_env()
63-
app = Sanic(dependency_manager.app_name)
66+
app = Sanic(dependency_manager.app_name, configure_logging=False)
6467

6568
if "COVERAGE_RUN" in environ:
6669
app.config.TOUCHUP = False
@@ -160,10 +163,18 @@ async def setup_rclone_validator(app: Sanic) -> None:
160163
@app.main_process_ready
161164
async def ready(app: Sanic) -> None:
162165
"""Application ready event handler."""
163-
logger.info("starting events background job.")
164166
if getattr(app.ctx, "solr_reindex", False):
167+
logger.info("Starting solr reindex, as required by migrations.")
165168
app.manager.manage("SolrReindex", solr_reindex, {"app_name": app.name}, transient=True)
166169

170+
@app.before_server_start
171+
async def logging_setup1(app: Sanic) -> None:
172+
configure_logging()
173+
174+
@app.main_process_ready
175+
async def logging_setup2(app: Sanic) -> None:
176+
configure_logging()
177+
167178
return app
168179

169180

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
"""Renku data service tasks."""
2+
3+
import renku_data_services.app_config.logging as logging
4+
5+
logging.configure_logging()

bases/renku_data_services/data_tasks/main.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,13 @@
55

66
import uvloop
77

8+
from renku_data_services.app_config.logging import getLogger
89
from renku_data_services.data_tasks.dependencies import DependencyManager
910
from renku_data_services.data_tasks.task_defs import all_tasks
1011
from renku_data_services.data_tasks.taskman import TaskDefininions, TaskManager
1112
from renku_data_services.data_tasks.tcp_handler import TcpHandler
1213

13-
14-
def configure_logging() -> None:
15-
"""Configures logging.
16-
17-
Log everything at level WARNING, except for our code that is set to INFO
18-
"""
19-
logging.basicConfig(level=logging.WARNING, format="%(asctime)s %(name)s %(levelname)s %(message)s")
20-
logging.getLogger("renku_data_services").setLevel(logging.INFO)
14+
logger = getLogger(__name__)
2115

2216

2317
async def log_tasks(logger: logging.Logger, tm: TaskManager, interval: int) -> None:
@@ -33,8 +27,6 @@ async def log_tasks(logger: logging.Logger, tm: TaskManager, interval: int) -> N
3327
async def main() -> None:
3428
"""Data tasks entry point."""
3529
dm = DependencyManager.from_env()
36-
configure_logging()
37-
logger = logging.getLogger("renku_data_services.data_tasks.main")
3830
logger.info(f"Config: {dm.config}")
3931

4032
tm = TaskManager(dm.config.max_retry_wait_seconds)

bases/renku_data_services/data_tasks/task_defs.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""The task definitions in form of coroutines."""
22

33
import asyncio
4-
import logging
54

65
from authzed.api.v1 import (
76
Consistency,
@@ -20,6 +19,7 @@
2019
import renku_data_services.authz.admin_sync as admin_sync
2120
import renku_data_services.search.core as search_core
2221
from renku_data_services import errors
22+
from renku_data_services.app_config import logging
2323
from renku_data_services.authz.authz import ResourceType, _AuthzConverter, _Relation
2424
from renku_data_services.authz.models import Scope
2525
from renku_data_services.base_models.core import InternalServiceAdmin, ServiceAdminId
@@ -104,7 +104,7 @@ async def generate_user_namespaces(dm: DependencyManager) -> None:
104104
async def sync_user_namespaces(dm: DependencyManager) -> None:
105105
"""Lists all user namespaces in the database and adds them to Authzed and the event queue."""
106106
user_namespaces = dm.group_repo._get_user_namespaces()
107-
logging.info("Start syncing user namespaces to the authorization DB and message queue")
107+
logger.info("Start syncing user namespaces to the authorization DB and message queue")
108108
num_authz: int = 0
109109
num_events: int = 0
110110
num_total: int = 0
@@ -124,14 +124,14 @@ async def sync_user_namespaces(dm: DependencyManager) -> None:
124124
except Exception as err:
125125
# NOTE: We do not rollback the authz changes here because it is OK if something is in Authz DB
126126
# but not in the message queue but not vice-versa.
127-
logging.error(f"Failed to sync user namespace {user_namespace} because {err}")
127+
logger.error(f"Failed to sync user namespace {user_namespace} because {err}")
128128
await tx.rollback()
129129
else:
130130
await tx.commit()
131131
finally:
132132
await session.close()
133-
logging.info(f"Wrote authorization changes for {num_authz}/{num_total} user namespaces")
134-
logging.info(f"Wrote to event queue database for {num_events}/{num_total} user namespaces")
133+
logger.info(f"Wrote authorization changes for {num_authz}/{num_total} user namespaces")
134+
logger.info(f"Wrote to event queue database for {num_events}/{num_total} user namespaces")
135135

136136

137137
async def bootstrap_user_namespaces(dm: DependencyManager) -> None:
@@ -152,7 +152,7 @@ async def bootstrap_user_namespaces(dm: DependencyManager) -> None:
152152
if await anext(rels, None) is not None:
153153
num_rels += 1
154154
if num_rels >= 5:
155-
logging.info(
155+
logger.info(
156156
"Found at least 5 user namespace in the authorization database, "
157157
"will not sync user namespaces to authorization."
158158
)
@@ -183,12 +183,12 @@ async def fix_mismatched_project_namespace_ids(dm: DependencyManager) -> None:
183183
)
184184
)
185185
async for rel in res:
186-
logging.info(f"Checking project namespace - group relation {rel} for correct group ID")
186+
logger.info(f"Checking project namespace - group relation {rel} for correct group ID")
187187
project_id = rel.relationship.resource.object_id
188188
try:
189189
project = await dm.project_repo.get_project(api_user, project_id)
190190
except errors.MissingResourceError:
191-
logging.info(f"Couldn't find project {project_id}, deleting relation")
191+
logger.info(f"Couldn't find project {project_id}, deleting relation")
192192
await dm.authz.client.WriteRelationships(
193193
WriteRelationshipsRequest(
194194
updates=[
@@ -206,7 +206,7 @@ async def fix_mismatched_project_namespace_ids(dm: DependencyManager) -> None:
206206
correct_group_id = project.namespace.underlying_resource_id
207207
authzed_group_id = rel.relationship.subject.object.object_id
208208
if authzed_group_id != correct_group_id:
209-
logging.info(
209+
logger.info(
210210
f"The project namespace ID in Authzed {authzed_group_id} "
211211
f"does not match the expected group ID {correct_group_id}, correcting it..."
212212
)

bases/renku_data_services/data_tasks/taskman.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from __future__ import annotations
44

55
import asyncio
6-
import logging
76
import math
87
import sys
98
from asyncio.tasks import Task
@@ -12,6 +11,8 @@
1211
from datetime import datetime, timedelta
1312
from typing import Any, final
1413

14+
from renku_data_services.app_config import logging
15+
1516
logger = logging.getLogger(__name__)
1617

1718
type TaskFactory = Callable[[], Coroutine[Any, Any, None]]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
"""Kubernetes Cache."""
2+
3+
import renku_data_services.app_config.logging as logging
4+
5+
logging.configure_logging()

bases/renku_data_services/k8s_cache/main.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
"""The entrypoint for the k8s cache service."""
22

33
import asyncio
4-
import logging
54

65
import kr8s
76

7+
from renku_data_services.app_config import logging
88
from renku_data_services.k8s.models import Cluster, ClusterId
99
from renku_data_services.k8s_cache.dependencies import DependencyManager
1010
from renku_data_services.k8s_watcher import K8sWatcher, k8s_object_handler
1111
from renku_data_services.notebooks.constants import AMALTHEA_SESSION_GVK, JUPYTER_SESSION_GVK
1212
from renku_data_services.session.constants import BUILD_RUN_GVK, TASK_RUN_GVK
1313

14+
logger = logging.getLogger(__name__)
15+
1416

1517
async def main() -> None:
1618
"""K8s cache entrypoint."""
1719

18-
logging.basicConfig(format="%(asctime)s %(levelname)s %(message)s", level=logging.INFO)
1920
dm = DependencyManager.from_env()
2021

2122
kr8s_api = await kr8s.asyncio.api()
@@ -31,7 +32,7 @@ async def main() -> None:
3132
db_cache=dm.k8s_cache,
3233
)
3334
await watcher.start()
34-
logging.info("started watching resources")
35+
logger.info("started watching resources")
3536
# create file for liveness probe
3637
with open("/tmp/cache_ready", "w") as f: # nosec B108
3738
f.write("ready")
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
"""Secrets storage."""
2+
3+
import renku_data_services.app_config.logging as logging
4+
5+
logging.configure_logging()

bases/renku_data_services/secrets_storage_api/main.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from sanic import Sanic
1010
from sanic.worker.loader import AppLoader
1111

12+
from renku_data_services.app_config import logging
1213
from renku_data_services.base_models.core import InternalServiceAdmin, ServiceAdminId
1314
from renku_data_services.secrets.core import rotate_encryption_keys
1415
from renku_data_services.secrets_storage_api.app import register_all_handlers
@@ -26,6 +27,11 @@ def create_app() -> Sanic:
2627
@app.main_process_start
2728
def main_process_start(app: Sanic) -> None:
2829
app.shared_ctx.rotation_lock = Lock()
30+
logging.configure_logging()
31+
32+
@app.before_server_start
33+
async def logging_setup1(app: Sanic) -> None:
34+
logging.configure_logging()
2935

3036
# Setup prometheus
3137
monitor(app, endpoint_type="url", multiprocess_mode="all", is_middleware=True).expose_endpoint()

0 commit comments

Comments
 (0)