-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy path_logging.py
More file actions
108 lines (89 loc) · 3.03 KB
/
_logging.py
File metadata and controls
108 lines (89 loc) · 3.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import os
import sys
from collections.abc import Sequence
from contextlib import contextmanager
from pathlib import Path
from typing import Any
import logfire
from dotenv import load_dotenv
from loguru import logger
__all__ = ["get_logger", "span"]
# Load environment variables
load_dotenv()
# Get the project root directory
PROJECT_ROOT = Path(__file__).parent.parent.absolute()
LOGS_DIR = PROJECT_ROOT / "logs"
# Create logs directory if it doesn't exist
os.makedirs(LOGS_DIR, exist_ok=True)
# Get log level from environment or use default
LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO").strip()
# Define log format that works with and without 'source' in extra
LOG_FORMAT = (
"<green>{process}:{level}: {time:YYYY-MM-DD at HH:mm:ss}</green> <blue>({name}::{function})</blue> {message}"
)
# Remove default handlers
logger.remove()
# Log to local filesystem as well,
# Keeping it here in case we want to use it sometimes it's more convenient to
# look for things using grep
logger.add(
sys.stdout,
format=LOG_FORMAT,
level=LOG_LEVEL,
colorize=True,
)
# Add file handlers
logger.add(
str(LOGS_DIR / "debug.log"),
format=LOG_FORMAT,
level="DEBUG",
rotation="1 day",
retention="1 year",
compression="zip",
enqueue=True, # Use a queue for thread-safe logging
)
logger.add(
str(LOGS_DIR / "app.log"),
format=LOG_FORMAT,
level=LOG_LEVEL,
rotation="1 day",
retention="1 year",
compression="zip",
enqueue=True, # Use a queue for thread-safe logging
)
# Add logfire handler if token is available
if os.environ.get("LOGFIRE_TOKEN"):
logfire_handler = logfire.loguru_handler()
logger.add(**logfire_handler)
logfire.configure(console=False)
# Log a test message to verify logging is working
logger.info("Logging initialized with level: {}", LOG_LEVEL)
logger.debug("Debug logging is enabled")
def get_logger(source: str) -> Any:
"""Get a logger instance bound with the source name."""
return logger.bind(source=source)
@contextmanager
def span(
msg_template: str, name: str | None = None, tags: Sequence[str] | None = None, **msg_template_kwargs: Any
) -> Any:
"""
Context manager for creating spans in logging.
Args:
msg_template (str): The message template for the span.
name (str | None): Optional name for the span.
tags (Sequence[str] | None): Optional tags for the span.
**msg_template_kwargs: Additional keyword arguments for the message template.
Yields:
Any: The span context manager or a dummy context manager.
"""
# Check if LOGFIRE_TOKEN environment variable is defined
if os.getenv("LOGFIRE_TOKEN"):
if tags:
# logs don't display on logfire dashboard if the type is not `str`
tags = [str(tag) for tag in tags]
# Use logfire.span if the environment variable is set
with logfire.span(msg_template, _span_name=name, _tags=tags, **msg_template_kwargs) as _span:
yield _span
else:
# Return a dummy context manager that does nothing
yield