Coverage for src / sentry_tool / monitoring.py: 95.65%
23 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-15 10:53 -0500
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-15 10:53 -0500
1"""Monitoring setup: Sentry error tracking and structlog logging.
3Logging goes to stderr to keep stdout clean for data output (piping).
4Sentry is initialized after logging for self-monitoring.
5DSN is read from SENTRY_DSN environment variable (optional for public distribution).
6"""
8import logging
9import os
10import sys
11from typing import Any
13import sentry_sdk
14import structlog
16from sentry_tool.__about__ import __version__
18_LOG_LEVELS: dict[str, int] = {
19 "debug": logging.DEBUG,
20 "info": logging.INFO,
21 "warning": logging.WARNING,
22 "error": logging.ERROR,
23 "critical": logging.CRITICAL,
24}
27def setup_logging(verbose: bool = False) -> None:
28 log_level = "debug" if verbose else "info"
30 structlog.configure(
31 processors=[
32 structlog.contextvars.merge_contextvars,
33 structlog.processors.add_log_level,
34 structlog.processors.TimeStamper(fmt="iso"),
35 structlog.dev.ConsoleRenderer(colors=sys.stderr.isatty()),
36 ],
37 wrapper_class=structlog.make_filtering_bound_logger(_LOG_LEVELS[log_level]),
38 context_class=dict,
39 logger_factory=structlog.PrintLoggerFactory(file=sys.stderr),
40 cache_logger_on_first_use=True,
41 )
44def get_logger(name: str | None = None) -> Any:
45 logger = structlog.get_logger()
46 if name:
47 logger = logger.bind(logger=name)
48 return logger
51def setup_sentry(environment: str = "local") -> None:
52 """Configure error tracking for this CLI tool instance.
54 Reads DSN from SENTRY_DSN environment variable. Skips initialization if unset,
55 allowing the tool to run without error tracking in public distributions.
56 """
57 dsn = os.environ.get("SENTRY_DSN")
58 if not dsn:
59 log = structlog.get_logger()
60 log.info("Sentry DSN not configured, skipping error tracking setup")
61 return
63 sentry_sdk.init(
64 dsn=dsn,
65 traces_sample_rate=0.03,
66 environment=environment,
67 release=__version__,
68 attach_stacktrace=True,
69 send_default_pii=False,
70 )