custom-python-logger 3.0.2__py3-none-any.whl → 4.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- custom_python_logger/__init__.py +7 -0
- custom_python_logger/consts.py +5 -0
- custom_python_logger/logger.py +33 -3
- {custom_python_logger-3.0.2.dist-info → custom_python_logger-4.0.1.dist-info}/METADATA +50 -5
- custom_python_logger-4.0.1.dist-info/RECORD +8 -0
- custom_python_logger-3.0.2.dist-info/RECORD +0 -8
- {custom_python_logger-3.0.2.dist-info → custom_python_logger-4.0.1.dist-info}/WHEEL +0 -0
- {custom_python_logger-3.0.2.dist-info → custom_python_logger-4.0.1.dist-info}/licenses/LICENSE +0 -0
- {custom_python_logger-3.0.2.dist-info → custom_python_logger-4.0.1.dist-info}/top_level.txt +0 -0
custom_python_logger/__init__.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from dotenv import load_dotenv
|
|
2
|
+
|
|
3
|
+
from custom_python_logger.consts import LOG_FORMAT_FILENAME, LOG_FORMAT_SHORTPATH
|
|
1
4
|
from custom_python_logger.logger import (
|
|
2
5
|
CustomLoggerAdapter,
|
|
3
6
|
CustomLoggerLevel,
|
|
@@ -7,6 +10,8 @@ from custom_python_logger.logger import (
|
|
|
7
10
|
yaml_pretty_format,
|
|
8
11
|
)
|
|
9
12
|
|
|
13
|
+
load_dotenv()
|
|
14
|
+
|
|
10
15
|
__all__ = [
|
|
11
16
|
"CustomLoggerAdapter",
|
|
12
17
|
"CustomLoggerLevel",
|
|
@@ -14,4 +19,6 @@ __all__ = [
|
|
|
14
19
|
"get_logger",
|
|
15
20
|
"json_pretty_format",
|
|
16
21
|
"yaml_pretty_format",
|
|
22
|
+
"LOG_FORMAT_SHORTPATH",
|
|
23
|
+
"LOG_FORMAT_FILENAME",
|
|
17
24
|
]
|
custom_python_logger/consts.py
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
|
|
3
|
+
LOG_FORMAT_FILENAME = "%(asctime)s | %(levelname)-9s | l.%(levelno)s | %(name)s | %(filename)s:%(lineno)s | %(message)s"
|
|
4
|
+
LOG_FORMAT_SHORTPATH = (
|
|
5
|
+
"%(asctime)s | %(levelname)-9s | l.%(levelno)s | %(name)s | %(shortpath)s:%(lineno)s | %(message)s"
|
|
6
|
+
)
|
|
7
|
+
|
|
3
8
|
LOG_COLORS = {
|
|
4
9
|
"DEBUG": "white",
|
|
5
10
|
"INFO": "green",
|
custom_python_logger/logger.py
CHANGED
|
@@ -10,7 +10,7 @@ from typing import Any
|
|
|
10
10
|
import yaml
|
|
11
11
|
from colorlog import ColoredFormatter
|
|
12
12
|
|
|
13
|
-
from custom_python_logger.consts import LOG_COLORS, CustomLoggerLevel
|
|
13
|
+
from custom_python_logger.consts import LOG_COLORS, LOG_FORMAT_FILENAME, CustomLoggerLevel
|
|
14
14
|
|
|
15
15
|
CUSTOM_LOGGER = "custom_logger"
|
|
16
16
|
|
|
@@ -48,6 +48,30 @@ def print_before_logger(project_name: str, sleep_time: float = 0.3) -> None:
|
|
|
48
48
|
time.sleep(sleep_time)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
class _ShortPathFilter(logging.Filter):
|
|
52
|
+
def __init__(self) -> None:
|
|
53
|
+
super().__init__()
|
|
54
|
+
self._project_name = os.getenv("PROJECT_NAME")
|
|
55
|
+
|
|
56
|
+
def filter(self, record: logging.LogRecord) -> bool:
|
|
57
|
+
if self._project_name and self._project_name in record.pathname:
|
|
58
|
+
record.shortpath = self._project_name + record.pathname.rsplit(self._project_name, 1)[1]
|
|
59
|
+
else:
|
|
60
|
+
record.shortpath = record.pathname
|
|
61
|
+
|
|
62
|
+
if ".venv" in record.pathname:
|
|
63
|
+
record.shortpath = ".venv" + record.pathname.rsplit(".venv", 1)[1]
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class _StripNamespaceFilter(logging.Filter):
|
|
68
|
+
def filter(self, record: logging.LogRecord) -> bool:
|
|
69
|
+
prefix = CUSTOM_LOGGER + "."
|
|
70
|
+
if record.name.startswith(prefix):
|
|
71
|
+
record.name = record.name[len(prefix) :]
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
|
|
51
75
|
class CustomLoggerAdapter(logging.LoggerAdapter):
|
|
52
76
|
def exception(self, msg: str, *args: Any, **kwargs: Any) -> None:
|
|
53
77
|
logging.addLevelName(CustomLoggerLevel.EXCEPTION.value, "EXCEPTION")
|
|
@@ -105,8 +129,11 @@ def add_console_handler(logger: Logger, log_format: str) -> None:
|
|
|
105
129
|
|
|
106
130
|
def get_logger(name: str, log_level: int | None = None, extra: dict | None = None) -> CustomLoggerAdapter:
|
|
107
131
|
custom_logger = logging.getLogger(CUSTOM_LOGGER)
|
|
132
|
+
|
|
108
133
|
full_name = f"{CUSTOM_LOGGER}.{name}"
|
|
109
|
-
|
|
134
|
+
underlying = logging.getLogger(full_name)
|
|
135
|
+
underlying.addFilter(_StripNamespaceFilter())
|
|
136
|
+
new_logger = CustomLoggerAdapter(underlying, extra=extra)
|
|
110
137
|
|
|
111
138
|
if log_level is None:
|
|
112
139
|
log_level = custom_logger.level
|
|
@@ -118,7 +145,7 @@ def get_logger(name: str, log_level: int | None = None, extra: dict | None = Non
|
|
|
118
145
|
def build_logger( # pylint: disable=R0913
|
|
119
146
|
project_name: str,
|
|
120
147
|
extra: dict[str, Any] | None = None,
|
|
121
|
-
log_format: str =
|
|
148
|
+
log_format: str = LOG_FORMAT_FILENAME,
|
|
122
149
|
log_level: int = logging.DEBUG,
|
|
123
150
|
log_file: bool = False,
|
|
124
151
|
log_file_path: str | None = None,
|
|
@@ -156,6 +183,9 @@ def build_logger( # pylint: disable=R0913
|
|
|
156
183
|
log_file_path = log_file_path.lower().replace(" ", "_")
|
|
157
184
|
add_file_handler(logger=root_logger, log_file_path=log_file_path, log_format=log_format)
|
|
158
185
|
|
|
186
|
+
for handler in root_logger.handlers:
|
|
187
|
+
handler.addFilter(_ShortPathFilter())
|
|
188
|
+
|
|
159
189
|
logger = CustomLoggerAdapter(logging.getLogger(CUSTOM_LOGGER), extra)
|
|
160
190
|
logger.setLevel(log_level)
|
|
161
191
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: custom-python-logger
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.1
|
|
4
4
|
Summary: A custom logger with color support and additional features.
|
|
5
5
|
Author: Avi Zaguri
|
|
6
6
|
License: MIT
|
|
@@ -42,6 +42,7 @@ Easily integrate structured, readable, and context-rich logging into your Python
|
|
|
42
42
|
- ✅ **Contextual Logging**: Add extra fields (like user, environment, etc.) to every log message.
|
|
43
43
|
- ✅ **UTC Support**: Optionally log timestamps in UTC for consistency across environments.
|
|
44
44
|
- ✅ **Pretty Formatting**: Built-in helpers for pretty-printing JSON and YAML data in logs.
|
|
45
|
+
- ✅ **Short Path Display**: Automatically trims log file paths to project-relative or `.venv`-relative format for cleaner output.
|
|
45
46
|
- ✅ **Easy Integration**: Simple API for getting a ready-to-use logger anywhere in your codebase.
|
|
46
47
|
|
|
47
48
|
---
|
|
@@ -80,6 +81,7 @@ logger.critical("This is a critical message.")
|
|
|
80
81
|
```
|
|
81
82
|
|
|
82
83
|
#### Advanced Usage
|
|
84
|
+
|
|
83
85
|
- Log to a file:
|
|
84
86
|
```python
|
|
85
87
|
from custom_python_logger import build_logger
|
|
@@ -111,19 +113,62 @@ logger.critical("This is a critical message.")
|
|
|
111
113
|
logger.info(yaml_pretty_format({'foo': 'bar'}))
|
|
112
114
|
```
|
|
113
115
|
|
|
114
|
-
-
|
|
116
|
+
- Use an existing logger with a custom name:
|
|
115
117
|
```python
|
|
116
118
|
from custom_python_logger import get_logger
|
|
117
119
|
|
|
118
120
|
logger = get_logger('some-name')
|
|
119
121
|
|
|
120
|
-
logger.debug("This is a debug message.")
|
|
121
|
-
logger.info("This is an info message.")
|
|
122
|
-
logger.step("This is a step message.")
|
|
122
|
+
logger.debug("This is a debug message.")
|
|
123
|
+
logger.info("This is an info message.")
|
|
124
|
+
logger.step("This is a step message.")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- Use a custom log format:
|
|
128
|
+
```python
|
|
129
|
+
from custom_python_logger import build_logger, LOG_FORMAT_FILENAME, LOG_FORMAT_SHORTPATH
|
|
130
|
+
|
|
131
|
+
# Default — shows project-relative or .venv-relative path:
|
|
132
|
+
# 2026-05-18 | INFO | l.20 | my_app | my_project/app/main.py:42 | message
|
|
133
|
+
logger = build_logger(project_name='MyApp', log_format=LOG_FORMAT_SHORTPATH)
|
|
134
|
+
|
|
135
|
+
# Classic — shows filename only (no path):
|
|
136
|
+
# 2026-05-18 | INFO | l.20 | my_app | main.py:42 | message
|
|
137
|
+
logger = build_logger(project_name='MyApp', log_format=LOG_FORMAT_FILENAME)
|
|
123
138
|
```
|
|
124
139
|
|
|
125
140
|
---
|
|
126
141
|
|
|
142
|
+
## 🗂️ Short Path Display
|
|
143
|
+
|
|
144
|
+
By default, `build_logger` uses `LOG_FORMAT_SHORTPATH`, which trims the file path in every log line:
|
|
145
|
+
|
|
146
|
+
| Path type | Raw `record.pathname` | Displayed as |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| Project file | `/home/user/my_project/app/main.py` | `my_project/app/main.py` |
|
|
149
|
+
| Dependency in `.venv` | `/home/user/my_project/.venv/lib/python3.13/site-packages/urllib3/pool.py` | `.venv/lib/python3.13/site-packages/urllib3/pool.py` |
|
|
150
|
+
| Unrecognised path | `/tmp/some_script.py` | `/tmp/some_script.py` (full path) |
|
|
151
|
+
|
|
152
|
+
### Setting your project name
|
|
153
|
+
|
|
154
|
+
The short-path logic uses the `PROJECT_NAME` environment variable to identify your project root.
|
|
155
|
+
Set it in your `.env` file (loaded automatically on import) or export it before running:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# .env
|
|
159
|
+
PROJECT_NAME=my_project
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# or inline
|
|
164
|
+
PROJECT_NAME=my_project python main.py
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
> **Note:** `custom-python-logger` calls `load_dotenv()` on import, which reads your `.env` file automatically.
|
|
168
|
+
> If you set `PROJECT_NAME` programmatically, do so **before** importing `custom_python_logger` to ensure it takes effect.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
127
172
|
## 🤝 Contributing
|
|
128
173
|
If you have a helpful tool, pattern, or improvement to suggest:
|
|
129
174
|
Fork the repo <br>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
custom_python_logger/__init__.py,sha256=88wm3t65rvclBgmVxHXG0Py5KwZioBK0L7W5I_CiRzw,515
|
|
2
|
+
custom_python_logger/consts.py,sha256=T2YcREZQiuLkujICXDGojSHbwgsDB-fNE8LQMsLWyZ8,698
|
|
3
|
+
custom_python_logger/logger.py,sha256=2ZQqpr10DdpO14yJtIU1HqK_7rX6sFWrs6LMl7hh6Ws,6903
|
|
4
|
+
custom_python_logger-4.0.1.dist-info/licenses/LICENSE,sha256=cSikHY6SZFsPZSBizCDAJ0-Bjjzxt-JtX6TVbKxwimo,1067
|
|
5
|
+
custom_python_logger-4.0.1.dist-info/METADATA,sha256=LRzrdBMNXsqa4WdUUT2Yn8eUXYS9-vucbgVoQdjyrl8,6249
|
|
6
|
+
custom_python_logger-4.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
7
|
+
custom_python_logger-4.0.1.dist-info/top_level.txt,sha256=lMihLuDQUTn0aSzzzbv9LZZTWTAap0IKpKabUHwOgks,21
|
|
8
|
+
custom_python_logger-4.0.1.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
custom_python_logger/__init__.py,sha256=weJwYyKZx1SGHnpv_jodeNOZOUIAuF7wjJSjp70zWG4,331
|
|
2
|
-
custom_python_logger/consts.py,sha256=ZIZL1Ir9jDHCHu4Vk9-cgja2QWWrIBBNdqOLCzPrFSU,445
|
|
3
|
-
custom_python_logger/logger.py,sha256=6HYY4PohPXjIFKJXH7iaiRi7epOmWQUim41mAlRqx7U,5974
|
|
4
|
-
custom_python_logger-3.0.2.dist-info/licenses/LICENSE,sha256=cSikHY6SZFsPZSBizCDAJ0-Bjjzxt-JtX6TVbKxwimo,1067
|
|
5
|
-
custom_python_logger-3.0.2.dist-info/METADATA,sha256=3dZl_c1d7vfDGi6l-56taI80bBNNhY0cczyOsbm8V0E,4492
|
|
6
|
-
custom_python_logger-3.0.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
7
|
-
custom_python_logger-3.0.2.dist-info/top_level.txt,sha256=lMihLuDQUTn0aSzzzbv9LZZTWTAap0IKpKabUHwOgks,21
|
|
8
|
-
custom_python_logger-3.0.2.dist-info/RECORD,,
|
|
File without changes
|
{custom_python_logger-3.0.2.dist-info → custom_python_logger-4.0.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|