custom-python-logger 2.0.0__tar.gz → 2.0.2__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.
Files changed (20) hide show
  1. {custom_python_logger-2.0.0/custom_python_logger.egg-info → custom_python_logger-2.0.2}/PKG-INFO +1 -1
  2. custom_python_logger-2.0.2/custom_python_logger/consts.py +16 -0
  3. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/custom_python_logger/logger.py +85 -67
  4. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/custom_python_logger/usage_example.py +1 -1
  5. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2/custom_python_logger.egg-info}/PKG-INFO +1 -1
  6. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/custom_python_logger.egg-info/SOURCES.txt +1 -0
  7. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/setup.py +1 -1
  8. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/LICENSE +0 -0
  9. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/MANIFEST.in +0 -0
  10. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/README.md +0 -0
  11. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/custom_python_logger/__init__.py +1 -1
  12. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/custom_python_logger.egg-info/dependency_links.txt +0 -0
  13. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/custom_python_logger.egg-info/requires.txt +0 -0
  14. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/custom_python_logger.egg-info/top_level.txt +0 -0
  15. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/pyproject.toml +0 -0
  16. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/requirements.txt +0 -0
  17. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/setup.cfg +0 -0
  18. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/tests/test_logger.py +0 -0
  19. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/tests/test_logger_pytest.py +0 -0
  20. {custom_python_logger-2.0.0 → custom_python_logger-2.0.2}/tests/test_usage_example_pytest.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: custom-python-logger
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: A custom logger with color support and additional features.
5
5
  Home-page: https://github.com/aviz92/custom-python-logger
6
6
  Author: Avi Zaguri
@@ -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,39 @@ import json
2
2
  import logging
3
3
  import os
4
4
  import time
5
- from logging import Logger, LoggerAdapter
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
12
13
 
13
- def get_project_path_by_file(marker: str = ".git") -> Path:
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"]
14
32
  path = Path(__file__).resolve()
15
33
  for parent in path.parents:
16
- if (parent / marker).exists():
17
- return parent
18
- raise RuntimeError(f"Project root with marker '{marker}' not found.")
34
+ for marker in markers:
35
+ if (parent / marker).exists():
36
+ return parent
37
+ raise RuntimeError(f'Project root with one of the markers: "{markers}" not found.')
19
38
 
20
39
 
21
40
  def print_before_logger(project_name: str) -> None:
@@ -30,16 +49,55 @@ def print_before_logger(project_name: str) -> None:
30
49
 
31
50
  class CustomLoggerAdapter(logging.LoggerAdapter):
32
51
  def exception(self, msg: str, *args, **kwargs):
33
- level_no = 45
34
- logging.addLevelName(level_no, "EXCEPTION")
52
+ logging.addLevelName(CustomLoggerLevel.EXCEPTION.value, "EXCEPTION")
35
53
  kwargs.setdefault("stacklevel", 2)
36
- self.log(level_no, msg, *args, exc_info=True, **kwargs)
54
+ self.log(CustomLoggerLevel.EXCEPTION.value, msg, *args, exc_info=True, **kwargs)
37
55
 
38
56
  def step(self, msg: str, *args, **kwargs):
39
- level_no = 25
40
- logging.addLevelName(level_no, "STEP")
57
+ logging.addLevelName(CustomLoggerLevel.STEP.value, "STEP")
41
58
  kwargs.setdefault("stacklevel", 2)
42
- self.log(level_no, msg, *args, exc_info=False, **kwargs)
59
+ self.log(CustomLoggerLevel.STEP.value, msg, *args, exc_info=False, **kwargs)
60
+
61
+
62
+ def clear_existing_handlers(logger: Logger) -> None:
63
+ for handler in logger.handlers[:]:
64
+ logger.removeHandler(handler)
65
+
66
+
67
+ def add_file_handler_if_specified(
68
+ logger: Logger,
69
+ log_file: bool,
70
+ log_file_path: Optional[str],
71
+ log_format: str,
72
+ ) -> None:
73
+ if log_file and log_file_path is not None:
74
+ log_file_formatter = logging.Formatter(log_format)
75
+
76
+ # Create directory if it doesn't exist
77
+ log_dir = os.path.dirname(log_file_path)
78
+ if log_dir and not os.path.exists(log_dir):
79
+ os.makedirs(log_dir)
80
+
81
+ file_handler = logging.FileHandler(log_file_path)
82
+
83
+ file_handler.setFormatter(log_file_formatter)
84
+ logger.addHandler(file_handler)
85
+
86
+
87
+ def add_console_handler_if_specified(
88
+ logger: Logger,
89
+ console_output: bool,
90
+ log_format: str
91
+ ):
92
+ if console_output:
93
+ log_console_formatter = ColoredFormatter(
94
+ "%(log_color)s " + log_format,
95
+ log_colors=LOG_COLORS,
96
+ )
97
+
98
+ console_handler = logging.StreamHandler()
99
+ console_handler.setFormatter(log_console_formatter)
100
+ logger.addHandler(console_handler)
43
101
 
44
102
 
45
103
  def configure_logging(
@@ -67,49 +125,26 @@ def configure_logging(
67
125
  root_logger = logging.getLogger()
68
126
  root_logger.setLevel(log_level)
69
127
 
70
- # Clear existing handlers
71
- for handler in root_logger.handlers[:]:
72
- root_logger.removeHandler(handler)
128
+ clear_existing_handlers(logger=root_logger)
73
129
 
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)
84
-
85
- file_handler.setFormatter(log_file_formatter)
86
- root_logger.addHandler(file_handler)
87
-
88
- # Add console handler if specified
89
- if console_output:
90
- # log_console_formatter = logging.Formatter('%(log_color)s ' + log_format)
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
- )
130
+ add_file_handler_if_specified(
131
+ logger=root_logger,
132
+ log_file=log_file,
133
+ log_file_path=log_file_path,
134
+ log_format=log_format,
135
+ )
103
136
 
104
- console_handler = logging.StreamHandler()
105
- console_handler.setFormatter(log_console_formatter)
106
- root_logger.addHandler(console_handler)
137
+ add_console_handler_if_specified(
138
+ logger=root_logger,
139
+ console_output=console_output,
140
+ log_format=log_format,
141
+ )
107
142
 
108
143
 
109
144
  def build_logger(
110
145
  project_name: str,
111
146
  extra: Optional[dict[str, Any]] = None,
112
- log_format: str = "%(asctime)s | %(levelname)-10s(l.%(levelno)s) | %(name)s | %(filename)s:%(lineno)s | %(message)s",
147
+ log_format: str = "%(asctime)s | %(levelname)-9s | l.%(levelno)s | %(name)s | %(filename)s:%(lineno)s | %(message)s",
113
148
  log_level: int = logging.INFO,
114
149
  log_file: bool = False,
115
150
  log_file_path: str = None,
@@ -128,12 +163,9 @@ def build_logger(
128
163
  log_file_path: Path to log file (if None, no file logging)
129
164
  console_output: Whether to output logs to console
130
165
  utc: Whether to use UTC time for log timestamps
131
-
132
166
  Returns:
133
167
  Configured logger
134
168
  """
135
- print_before_logger(project_name=project_name)
136
-
137
169
  if not log_file_path:
138
170
  log_file_path = f"{get_project_path_by_file()}/logs/{project_name}.log"
139
171
  log_file_path = log_file_path.lower().replace(" ", "_")
@@ -147,7 +179,7 @@ def build_logger(
147
179
  utc=utc,
148
180
  )
149
181
 
150
- logger = logging.getLogger()
182
+ logger = logging.getLogger(project_name)
151
183
 
152
184
  if log_level is not None:
153
185
  logger.setLevel(log_level)
@@ -155,19 +187,5 @@ def build_logger(
155
187
  return CustomLoggerAdapter(logger, extra)
156
188
 
157
189
 
158
- def get_logger(name: str) -> CustomLoggerAdapter:
159
- return CustomLoggerAdapter(logging.getLogger(name), {})
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
- )
190
+ def get_logger(name: str, extra: Optional[dict] = None) -> CustomLoggerAdapter:
191
+ return CustomLoggerAdapter(logging.getLogger(name), extra=extra)
@@ -5,7 +5,7 @@ from custom_python_logger import build_logger, get_logger
5
5
 
6
6
  class LoggerTest:
7
7
  def __init__(self):
8
- self.logger = get_logger(self.__class__.__name__)
8
+ self.logger = get_logger(self.__class__.__name__, extra={"class": self.__class__.__name__})
9
9
 
10
10
  def main(self):
11
11
  self.logger.debug("Hello World")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: custom-python-logger
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: A custom logger with color support and additional features.
5
5
  Home-page: https://github.com/aviz92/custom-python-logger
6
6
  Author: Avi Zaguri
@@ -5,6 +5,7 @@ pyproject.toml
5
5
  requirements.txt
6
6
  setup.py
7
7
  custom_python_logger/__init__.py
8
+ custom_python_logger/consts.py
8
9
  custom_python_logger/logger.py
9
10
  custom_python_logger/usage_example.py
10
11
  custom_python_logger.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
- package_version = '2.0.0'
3
+ package_version = '2.0.2'
4
4
 
5
5
  package_name = 'custom-python-logger'
6
6
  package_description = 'A custom logger with color support and additional features.'
@@ -7,9 +7,9 @@ from custom_python_logger.logger import (
7
7
  )
8
8
 
9
9
  __all__ = [
10
+ "CustomLoggerAdapter",
10
11
  "build_logger",
11
12
  "get_logger",
12
- "CustomLoggerAdapter",
13
13
  "json_pretty_format",
14
14
  "yaml_pretty_format",
15
15
  ]