custom-python-logger 2.0.1__tar.gz → 2.0.3__tar.gz
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-2.0.1/custom_python_logger.egg-info → custom_python_logger-2.0.3}/PKG-INFO +1 -1
- custom_python_logger-2.0.3/custom_python_logger/consts.py +16 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/custom_python_logger/logger.py +87 -64
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3/custom_python_logger.egg-info}/PKG-INFO +1 -1
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/custom_python_logger.egg-info/SOURCES.txt +1 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/setup.py +1 -1
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/LICENSE +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/MANIFEST.in +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/README.md +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/custom_python_logger/__init__.py +1 -1
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/custom_python_logger/usage_example.py +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/custom_python_logger.egg-info/dependency_links.txt +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/custom_python_logger.egg-info/requires.txt +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/custom_python_logger.egg-info/top_level.txt +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/pyproject.toml +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/requirements.txt +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/setup.cfg +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/tests/test_logger.py +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/tests/test_logger_pytest.py +0 -0
- {custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/tests/test_usage_example_pytest.py +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
LOG_COLORS = {
|
|
4
|
+
"DEBUG": "white",
|
|
5
|
+
"INFO": "green",
|
|
6
|
+
"WARNING": "yellow",
|
|
7
|
+
"STEP": "blue",
|
|
8
|
+
"ERROR": "red,bold",
|
|
9
|
+
"EXCEPTION": "light_red,bold",
|
|
10
|
+
"CRITICAL": "red,bg_white",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CustomLoggerLevel(Enum):
|
|
15
|
+
EXCEPTION = 45
|
|
16
|
+
STEP = 25
|
|
@@ -2,20 +2,44 @@ import json
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import time
|
|
5
|
-
from logging import Logger
|
|
5
|
+
from logging import Logger
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any, Callable, Optional
|
|
8
8
|
|
|
9
9
|
import yaml
|
|
10
10
|
from colorlog import ColoredFormatter
|
|
11
11
|
|
|
12
|
+
from custom_python_logger.consts import LOG_COLORS, CustomLoggerLevel
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def json_pretty_format(
|
|
16
|
+
data: Any, indent: int = 4, sort_keys: bool = True, default: Callable = None
|
|
17
|
+
) -> str:
|
|
18
|
+
return json.dumps(data, indent=indent, sort_keys=sort_keys, default=default)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def yaml_pretty_format(
|
|
22
|
+
data: Any, indent: int = 4, sort_keys: bool = False, allow_unicode=True
|
|
23
|
+
) -> str:
|
|
24
|
+
return yaml.dump(
|
|
25
|
+
data, sort_keys=sort_keys, indent=indent, allow_unicode=allow_unicode
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_project_path_by_file(markers: Optional[list[str]] = None) -> Path:
|
|
30
|
+
if not markers:
|
|
31
|
+
markers = ["pyproject.toml", "setup.py", ".git", "requirements.txt", ".gitignore", ".github", ".gitlab"]
|
|
32
|
+
path = Path(__file__).resolve() if "__file__" in globals() else Path.cwd().resolve()
|
|
33
|
+
|
|
34
|
+
for marker in markers:
|
|
35
|
+
if (path / marker).exists():
|
|
36
|
+
return path
|
|
12
37
|
|
|
13
|
-
def get_project_path_by_file(marker: str = ".git") -> Path:
|
|
14
|
-
path = Path(__file__).resolve()
|
|
15
38
|
for parent in path.parents:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
39
|
+
for marker in markers:
|
|
40
|
+
if (parent / marker).exists():
|
|
41
|
+
return parent
|
|
42
|
+
raise RuntimeError(f'Project root with one of the markers: "{markers}" not found.')
|
|
19
43
|
|
|
20
44
|
|
|
21
45
|
def print_before_logger(project_name: str) -> None:
|
|
@@ -30,16 +54,55 @@ def print_before_logger(project_name: str) -> None:
|
|
|
30
54
|
|
|
31
55
|
class CustomLoggerAdapter(logging.LoggerAdapter):
|
|
32
56
|
def exception(self, msg: str, *args, **kwargs):
|
|
33
|
-
|
|
34
|
-
logging.addLevelName(level_no, "EXCEPTION")
|
|
57
|
+
logging.addLevelName(CustomLoggerLevel.EXCEPTION.value, "EXCEPTION")
|
|
35
58
|
kwargs.setdefault("stacklevel", 2)
|
|
36
|
-
self.log(
|
|
59
|
+
self.log(CustomLoggerLevel.EXCEPTION.value, msg, *args, exc_info=True, **kwargs)
|
|
37
60
|
|
|
38
61
|
def step(self, msg: str, *args, **kwargs):
|
|
39
|
-
|
|
40
|
-
logging.addLevelName(level_no, "STEP")
|
|
62
|
+
logging.addLevelName(CustomLoggerLevel.STEP.value, "STEP")
|
|
41
63
|
kwargs.setdefault("stacklevel", 2)
|
|
42
|
-
self.log(
|
|
64
|
+
self.log(CustomLoggerLevel.STEP.value, msg, *args, exc_info=False, **kwargs)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def clear_existing_handlers(logger: Logger) -> None:
|
|
68
|
+
for handler in logger.handlers[:]:
|
|
69
|
+
logger.removeHandler(handler)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def add_file_handler_if_specified(
|
|
73
|
+
logger: Logger,
|
|
74
|
+
log_file: bool,
|
|
75
|
+
log_file_path: Optional[str],
|
|
76
|
+
log_format: str,
|
|
77
|
+
) -> None:
|
|
78
|
+
if log_file and log_file_path is not None:
|
|
79
|
+
log_file_formatter = logging.Formatter(log_format)
|
|
80
|
+
|
|
81
|
+
# Create directory if it doesn't exist
|
|
82
|
+
log_dir = os.path.dirname(log_file_path)
|
|
83
|
+
if log_dir and not os.path.exists(log_dir):
|
|
84
|
+
os.makedirs(log_dir)
|
|
85
|
+
|
|
86
|
+
file_handler = logging.FileHandler(log_file_path)
|
|
87
|
+
|
|
88
|
+
file_handler.setFormatter(log_file_formatter)
|
|
89
|
+
logger.addHandler(file_handler)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def add_console_handler_if_specified(
|
|
93
|
+
logger: Logger,
|
|
94
|
+
console_output: bool,
|
|
95
|
+
log_format: str
|
|
96
|
+
):
|
|
97
|
+
if console_output:
|
|
98
|
+
log_console_formatter = ColoredFormatter(
|
|
99
|
+
"%(log_color)s " + log_format,
|
|
100
|
+
log_colors=LOG_COLORS,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
console_handler = logging.StreamHandler()
|
|
104
|
+
console_handler.setFormatter(log_console_formatter)
|
|
105
|
+
logger.addHandler(console_handler)
|
|
43
106
|
|
|
44
107
|
|
|
45
108
|
def configure_logging(
|
|
@@ -67,43 +130,20 @@ def configure_logging(
|
|
|
67
130
|
root_logger = logging.getLogger()
|
|
68
131
|
root_logger.setLevel(log_level)
|
|
69
132
|
|
|
70
|
-
|
|
71
|
-
for handler in root_logger.handlers[:]:
|
|
72
|
-
root_logger.removeHandler(handler)
|
|
73
|
-
|
|
74
|
-
# Add file handler if specified
|
|
75
|
-
if log_file and log_file_path is not None:
|
|
76
|
-
log_file_formatter = logging.Formatter(log_format)
|
|
77
|
-
|
|
78
|
-
# Create directory if it doesn't exist
|
|
79
|
-
log_dir = os.path.dirname(log_file_path)
|
|
80
|
-
if log_dir and not os.path.exists(log_dir):
|
|
81
|
-
os.makedirs(log_dir)
|
|
82
|
-
|
|
83
|
-
file_handler = logging.FileHandler(log_file_path)
|
|
133
|
+
clear_existing_handlers(logger=root_logger)
|
|
84
134
|
|
|
85
|
-
|
|
86
|
-
root_logger
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
log_console_formatter = ColoredFormatter(
|
|
92
|
-
"%(log_color)s " + log_format,
|
|
93
|
-
log_colors={
|
|
94
|
-
"DEBUG": "white",
|
|
95
|
-
"INFO": "green",
|
|
96
|
-
"WARNING": "yellow",
|
|
97
|
-
"STEP": "blue",
|
|
98
|
-
"ERROR": "red,bold",
|
|
99
|
-
"EXCEPTION": "light_red,bold",
|
|
100
|
-
"CRITICAL": "red,bg_white",
|
|
101
|
-
},
|
|
102
|
-
)
|
|
135
|
+
add_file_handler_if_specified(
|
|
136
|
+
logger=root_logger,
|
|
137
|
+
log_file=log_file,
|
|
138
|
+
log_file_path=log_file_path,
|
|
139
|
+
log_format=log_format,
|
|
140
|
+
)
|
|
103
141
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
142
|
+
add_console_handler_if_specified(
|
|
143
|
+
logger=root_logger,
|
|
144
|
+
console_output=console_output,
|
|
145
|
+
log_format=log_format,
|
|
146
|
+
)
|
|
107
147
|
|
|
108
148
|
|
|
109
149
|
def build_logger(
|
|
@@ -128,12 +168,9 @@ def build_logger(
|
|
|
128
168
|
log_file_path: Path to log file (if None, no file logging)
|
|
129
169
|
console_output: Whether to output logs to console
|
|
130
170
|
utc: Whether to use UTC time for log timestamps
|
|
131
|
-
|
|
132
171
|
Returns:
|
|
133
172
|
Configured logger
|
|
134
173
|
"""
|
|
135
|
-
print_before_logger(project_name=project_name)
|
|
136
|
-
|
|
137
174
|
if not log_file_path:
|
|
138
175
|
log_file_path = f"{get_project_path_by_file()}/logs/{project_name}.log"
|
|
139
176
|
log_file_path = log_file_path.lower().replace(" ", "_")
|
|
@@ -157,17 +194,3 @@ def build_logger(
|
|
|
157
194
|
|
|
158
195
|
def get_logger(name: str, extra: Optional[dict] = None) -> CustomLoggerAdapter:
|
|
159
196
|
return CustomLoggerAdapter(logging.getLogger(name), extra=extra)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def json_pretty_format(
|
|
163
|
-
data: Any, indent: int = 4, sort_keys: bool = True, default: Callable = None
|
|
164
|
-
) -> str:
|
|
165
|
-
return json.dumps(data, indent=indent, sort_keys=sort_keys, default=default)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
def yaml_pretty_format(
|
|
169
|
-
data: Any, indent: int = 4, sort_keys: bool = False, allow_unicode=True
|
|
170
|
-
) -> str:
|
|
171
|
-
return yaml.dump(
|
|
172
|
-
data, sort_keys=sort_keys, indent=indent, allow_unicode=allow_unicode
|
|
173
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/custom_python_logger/usage_example.py
RENAMED
|
File without changes
|
|
File without changes
|
{custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/custom_python_logger.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{custom_python_logger-2.0.1 → custom_python_logger-2.0.3}/tests/test_usage_example_pytest.py
RENAMED
|
File without changes
|