custom-python-logger 1.0.11__tar.gz → 2.0.0__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-1.0.11/custom_python_logger.egg-info → custom_python_logger-2.0.0}/PKG-INFO +25 -11
  2. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/README.md +24 -10
  3. custom_python_logger-2.0.0/custom_python_logger/__init__.py +15 -0
  4. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/custom_python_logger/logger.py +48 -46
  5. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/custom_python_logger/usage_example.py +9 -7
  6. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0/custom_python_logger.egg-info}/PKG-INFO +25 -11
  7. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/custom_python_logger.egg-info/SOURCES.txt +3 -1
  8. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/setup.py +1 -1
  9. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/tests/test_logger.py +4 -4
  10. custom_python_logger-2.0.0/tests/test_logger_pytest.py +126 -0
  11. custom_python_logger-2.0.0/tests/test_usage_example_pytest.py +8 -0
  12. custom_python_logger-1.0.11/custom_python_logger/__init__.py +0 -10
  13. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/LICENSE +0 -0
  14. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/MANIFEST.in +0 -0
  15. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/custom_python_logger.egg-info/dependency_links.txt +0 -0
  16. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/custom_python_logger.egg-info/requires.txt +0 -0
  17. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/custom_python_logger.egg-info/top_level.txt +0 -0
  18. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/pyproject.toml +0 -0
  19. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/requirements.txt +0 -0
  20. {custom_python_logger-1.0.11 → custom_python_logger-2.0.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: custom-python-logger
3
- Version: 1.0.11
3
+ Version: 2.0.0
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
@@ -54,9 +54,9 @@ Here's a quick example of how to use `custom-python-logger` in your project:
54
54
 
55
55
  ```python
56
56
  import logging
57
- from custom_python_logger import get_logger, CustomLoggerAdapter
57
+ from custom_python_logger import build_logger, CustomLoggerAdapter
58
58
 
59
- logger: CustomLoggerAdapter = get_logger(
59
+ logger: CustomLoggerAdapter = build_logger(
60
60
  project_name='Logger Project Test',
61
61
  log_level=logging.DEBUG,
62
62
  log_file=True,
@@ -78,32 +78,46 @@ logger.critical("This is a critical message.")
78
78
  #### Advanced Usage
79
79
  - Log to a file:
80
80
  ```python
81
- from custom_python_logger import get_logger, CustomLoggerAdapter
81
+ from custom_python_logger import build_logger
82
82
 
83
- logger = get_logger(project_name='MyApp', log_file=True)
83
+ logger = build_logger(project_name='MyApp', log_file=True)
84
84
  ```
85
+
85
86
  - Use UTC timestamps:
86
87
  ```python
87
- from custom_python_logger import get_logger, CustomLoggerAdapter
88
+ from custom_python_logger import build_logger
88
89
 
89
- logger = get_logger(project_name='MyApp', log_file=True, utc=True)
90
+ logger = build_logger(project_name='MyApp', log_file=True, utc=True)
90
91
  ```
92
+
91
93
  - Add extra context:
92
94
  ```python
93
- from custom_python_logger import get_logger, CustomLoggerAdapter
95
+ from custom_python_logger import build_logger
94
96
 
95
- logger = get_logger(project_name='MyApp', log_file=True, utc=True, extra={'user': 'alice'})
97
+ logger = build_logger(project_name='MyApp', log_file=True, utc=True, extra={'user': 'alice'})
96
98
  ```
99
+
97
100
  - Pretty-print JSON or YAML:
98
101
  ```python
99
- from custom_python_logger import get_logger, CustomLoggerAdapter, json_pretty_format, yaml_pretty_format
102
+ from custom_python_logger import build_logger, json_pretty_format, yaml_pretty_format
100
103
 
101
- logger = get_logger(project_name='MyApp', utc=True, log_file=True)
104
+ logger = build_logger(project_name='MyApp', utc=True, log_file=True)
102
105
 
103
106
  logger.info(json_pretty_format({'foo': 'bar'}))
104
107
  logger.info(yaml_pretty_format({'foo': 'bar'}))
105
108
  ```
106
109
 
110
+ - use an existing logger (CustomLoggerAdapter) and set a custom name:
111
+ ```python
112
+ from custom_python_logger import get_logger
113
+
114
+ logger = get_logger('some-name')
115
+
116
+ logger.debug("This is a debug message.")
117
+ logger.info("This is an info message.")
118
+ logger.step("This is a step message.")
119
+ ```
120
+
107
121
  ---
108
122
 
109
123
  ## 🤝 Contributing
@@ -27,9 +27,9 @@ Here's a quick example of how to use `custom-python-logger` in your project:
27
27
 
28
28
  ```python
29
29
  import logging
30
- from custom_python_logger import get_logger, CustomLoggerAdapter
30
+ from custom_python_logger import build_logger, CustomLoggerAdapter
31
31
 
32
- logger: CustomLoggerAdapter = get_logger(
32
+ logger: CustomLoggerAdapter = build_logger(
33
33
  project_name='Logger Project Test',
34
34
  log_level=logging.DEBUG,
35
35
  log_file=True,
@@ -51,32 +51,46 @@ logger.critical("This is a critical message.")
51
51
  #### Advanced Usage
52
52
  - Log to a file:
53
53
  ```python
54
- from custom_python_logger import get_logger, CustomLoggerAdapter
54
+ from custom_python_logger import build_logger
55
55
 
56
- logger = get_logger(project_name='MyApp', log_file=True)
56
+ logger = build_logger(project_name='MyApp', log_file=True)
57
57
  ```
58
+
58
59
  - Use UTC timestamps:
59
60
  ```python
60
- from custom_python_logger import get_logger, CustomLoggerAdapter
61
+ from custom_python_logger import build_logger
61
62
 
62
- logger = get_logger(project_name='MyApp', log_file=True, utc=True)
63
+ logger = build_logger(project_name='MyApp', log_file=True, utc=True)
63
64
  ```
65
+
64
66
  - Add extra context:
65
67
  ```python
66
- from custom_python_logger import get_logger, CustomLoggerAdapter
68
+ from custom_python_logger import build_logger
67
69
 
68
- logger = get_logger(project_name='MyApp', log_file=True, utc=True, extra={'user': 'alice'})
70
+ logger = build_logger(project_name='MyApp', log_file=True, utc=True, extra={'user': 'alice'})
69
71
  ```
72
+
70
73
  - Pretty-print JSON or YAML:
71
74
  ```python
72
- from custom_python_logger import get_logger, CustomLoggerAdapter, json_pretty_format, yaml_pretty_format
75
+ from custom_python_logger import build_logger, json_pretty_format, yaml_pretty_format
73
76
 
74
- logger = get_logger(project_name='MyApp', utc=True, log_file=True)
77
+ logger = build_logger(project_name='MyApp', utc=True, log_file=True)
75
78
 
76
79
  logger.info(json_pretty_format({'foo': 'bar'}))
77
80
  logger.info(yaml_pretty_format({'foo': 'bar'}))
78
81
  ```
79
82
 
83
+ - use an existing logger (CustomLoggerAdapter) and set a custom name:
84
+ ```python
85
+ from custom_python_logger import get_logger
86
+
87
+ logger = get_logger('some-name')
88
+
89
+ logger.debug("This is a debug message.")
90
+ logger.info("This is an info message.")
91
+ logger.step("This is a step message.")
92
+ ```
93
+
80
94
  ---
81
95
 
82
96
  ## 🤝 Contributing
@@ -0,0 +1,15 @@
1
+ from custom_python_logger.logger import (
2
+ CustomLoggerAdapter,
3
+ build_logger,
4
+ get_logger,
5
+ json_pretty_format,
6
+ yaml_pretty_format,
7
+ )
8
+
9
+ __all__ = [
10
+ "build_logger",
11
+ "get_logger",
12
+ "CustomLoggerAdapter",
13
+ "json_pretty_format",
14
+ "yaml_pretty_format",
15
+ ]
@@ -1,19 +1,21 @@
1
- # logger.py
2
1
  import json
3
2
  import logging
4
3
  import os
5
4
  import time
6
- from logging import LoggerAdapter, Logger
5
+ from logging import Logger, LoggerAdapter
7
6
  from pathlib import Path
8
- from typing import Optional, Any
7
+ from typing import Any, Callable, Optional
8
+
9
9
  import yaml
10
10
  from colorlog import ColoredFormatter
11
11
 
12
12
 
13
- def get_root_project_path() -> Path:
14
- if 'venv' in str(Path(__file__)):
15
- return Path(__file__).parents[5]
16
- return Path(__file__).parent
13
+ def get_project_path_by_file(marker: str = ".git") -> Path:
14
+ path = Path(__file__).resolve()
15
+ for parent in path.parents:
16
+ if (parent / marker).exists():
17
+ return parent
18
+ raise RuntimeError(f"Project root with marker '{marker}' not found.")
17
19
 
18
20
 
19
21
  def print_before_logger(project_name: str) -> None:
@@ -30,23 +32,23 @@ class CustomLoggerAdapter(logging.LoggerAdapter):
30
32
  def exception(self, msg: str, *args, **kwargs):
31
33
  level_no = 45
32
34
  logging.addLevelName(level_no, "EXCEPTION")
33
- kwargs.setdefault('stacklevel', 2)
35
+ kwargs.setdefault("stacklevel", 2)
34
36
  self.log(level_no, msg, *args, exc_info=True, **kwargs)
35
37
 
36
38
  def step(self, msg: str, *args, **kwargs):
37
39
  level_no = 25
38
40
  logging.addLevelName(level_no, "STEP")
39
- kwargs.setdefault('stacklevel', 2)
41
+ kwargs.setdefault("stacklevel", 2)
40
42
  self.log(level_no, msg, *args, exc_info=False, **kwargs)
41
43
 
42
44
 
43
45
  def configure_logging(
44
- log_format: str,
45
- utc: bool,
46
- log_level: int = logging.INFO,
47
- log_file: bool = False,
48
- log_file_path: Optional[str] = None,
49
- console_output: bool = True,
46
+ log_format: str,
47
+ utc: bool,
48
+ log_level: int = logging.INFO,
49
+ log_file: bool = False,
50
+ log_file_path: Optional[str] = None,
51
+ console_output: bool = True,
50
52
  ) -> None:
51
53
  """
52
54
  Configure global logging settings.
@@ -87,16 +89,16 @@ def configure_logging(
87
89
  if console_output:
88
90
  # log_console_formatter = logging.Formatter('%(log_color)s ' + log_format)
89
91
  log_console_formatter = ColoredFormatter(
90
- '%(log_color)s ' + log_format,
92
+ "%(log_color)s " + log_format,
91
93
  log_colors={
92
- 'DEBUG': 'white',
93
- 'INFO': 'green',
94
- 'WARNING': 'yellow',
95
- 'STEP': 'blue',
96
- 'ERROR': 'red,bold',
97
- 'EXCEPTION': 'light_red,bold',
98
- 'CRITICAL': 'red,bg_white',
99
- }
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
+ },
100
102
  )
101
103
 
102
104
  console_handler = logging.StreamHandler()
@@ -104,16 +106,16 @@ def configure_logging(
104
106
  root_logger.addHandler(console_handler)
105
107
 
106
108
 
107
- def get_logger(
108
- project_name: str,
109
- extra: Optional[dict[str, Any]] = None,
110
- log_format: str = "%(asctime)s | %(levelname)-10s(l.%(levelno)s) | %(filename)s:%(lineno)s | %(message)s",
111
- log_level: int = logging.INFO,
112
- log_file: bool = False,
113
- log_file_path: str = None,
114
- console_output: bool = True,
115
- utc: bool = False,
116
- ) -> CustomLoggerAdapter[Logger | LoggerAdapter[Any] | Any] | Logger:
109
+ def build_logger(
110
+ project_name: str,
111
+ 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",
113
+ log_level: int = logging.INFO,
114
+ log_file: bool = False,
115
+ log_file_path: str = None,
116
+ console_output: bool = True,
117
+ utc: bool = False,
118
+ ) -> CustomLoggerAdapter | Logger:
117
119
  """
118
120
  Get a named logger with optional extra context.
119
121
 
@@ -133,8 +135,8 @@ def get_logger(
133
135
  print_before_logger(project_name=project_name)
134
136
 
135
137
  if not log_file_path:
136
- log_file_path = f'{get_root_project_path()}/logs/{project_name}.log'
137
- log_file_path = log_file_path.lower().replace(' ', '_')
138
+ log_file_path = f"{get_project_path_by_file()}/logs/{project_name}.log"
139
+ log_file_path = log_file_path.lower().replace(" ", "_")
138
140
 
139
141
  configure_logging(
140
142
  log_level=logging.DEBUG,
@@ -142,7 +144,7 @@ def get_logger(
142
144
  log_file=log_file,
143
145
  log_file_path=log_file_path,
144
146
  console_output=console_output,
145
- utc=utc
147
+ utc=utc,
146
148
  )
147
149
 
148
150
  logger = logging.getLogger()
@@ -153,19 +155,19 @@ def get_logger(
153
155
  return CustomLoggerAdapter(logger, extra)
154
156
 
155
157
 
158
+ def get_logger(name: str) -> CustomLoggerAdapter:
159
+ return CustomLoggerAdapter(logging.getLogger(name), {})
160
+
161
+
156
162
  def json_pretty_format(
157
- data: any,
158
- indent: int = 4,
159
- sort_keys: bool = True,
160
- default: callable = None
163
+ data: Any, indent: int = 4, sort_keys: bool = True, default: Callable = None
161
164
  ) -> str:
162
165
  return json.dumps(data, indent=indent, sort_keys=sort_keys, default=default)
163
166
 
164
167
 
165
168
  def yaml_pretty_format(
166
- data: any,
167
- indent: int = 4,
168
- sort_keys: bool = False,
169
- allow_unicode=True
169
+ data: Any, indent: int = 4, sort_keys: bool = False, allow_unicode=True
170
170
  ) -> str:
171
- return yaml.dump(data, sort_keys=sort_keys, indent=indent, allow_unicode=allow_unicode)
171
+ return yaml.dump(
172
+ data, sort_keys=sort_keys, indent=indent, allow_unicode=allow_unicode
173
+ )
@@ -1,19 +1,21 @@
1
1
  import logging
2
- from custom_python_logger import get_logger
2
+
3
+ from custom_python_logger import build_logger, get_logger
3
4
 
4
5
 
5
6
  class LoggerTest:
6
7
  def __init__(self):
7
- self.logger = logging.getLogger(self.__class__.__name__)
8
+ self.logger = get_logger(self.__class__.__name__)
8
9
 
9
10
  def main(self):
10
- self.logger.info('Hello World')
11
- self.logger.debug('Hello World')
11
+ self.logger.debug("Hello World")
12
+ self.logger.info("Hello World")
13
+ self.logger.step("Hello World")
12
14
 
13
15
 
14
16
  def main():
15
- logger = get_logger(
16
- project_name='Logger Project Test',
17
+ logger = build_logger(
18
+ project_name="Logger Project Test",
17
19
  log_level=logging.DEBUG,
18
20
  log_file=True,
19
21
  # extra={'user': 'test_user'}
@@ -35,5 +37,5 @@ def main():
35
37
  logger_test.main()
36
38
 
37
39
 
38
- if __name__ == '__main__':
40
+ if __name__ == "__main__":
39
41
  main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: custom-python-logger
3
- Version: 1.0.11
3
+ Version: 2.0.0
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
@@ -54,9 +54,9 @@ Here's a quick example of how to use `custom-python-logger` in your project:
54
54
 
55
55
  ```python
56
56
  import logging
57
- from custom_python_logger import get_logger, CustomLoggerAdapter
57
+ from custom_python_logger import build_logger, CustomLoggerAdapter
58
58
 
59
- logger: CustomLoggerAdapter = get_logger(
59
+ logger: CustomLoggerAdapter = build_logger(
60
60
  project_name='Logger Project Test',
61
61
  log_level=logging.DEBUG,
62
62
  log_file=True,
@@ -78,32 +78,46 @@ logger.critical("This is a critical message.")
78
78
  #### Advanced Usage
79
79
  - Log to a file:
80
80
  ```python
81
- from custom_python_logger import get_logger, CustomLoggerAdapter
81
+ from custom_python_logger import build_logger
82
82
 
83
- logger = get_logger(project_name='MyApp', log_file=True)
83
+ logger = build_logger(project_name='MyApp', log_file=True)
84
84
  ```
85
+
85
86
  - Use UTC timestamps:
86
87
  ```python
87
- from custom_python_logger import get_logger, CustomLoggerAdapter
88
+ from custom_python_logger import build_logger
88
89
 
89
- logger = get_logger(project_name='MyApp', log_file=True, utc=True)
90
+ logger = build_logger(project_name='MyApp', log_file=True, utc=True)
90
91
  ```
92
+
91
93
  - Add extra context:
92
94
  ```python
93
- from custom_python_logger import get_logger, CustomLoggerAdapter
95
+ from custom_python_logger import build_logger
94
96
 
95
- logger = get_logger(project_name='MyApp', log_file=True, utc=True, extra={'user': 'alice'})
97
+ logger = build_logger(project_name='MyApp', log_file=True, utc=True, extra={'user': 'alice'})
96
98
  ```
99
+
97
100
  - Pretty-print JSON or YAML:
98
101
  ```python
99
- from custom_python_logger import get_logger, CustomLoggerAdapter, json_pretty_format, yaml_pretty_format
102
+ from custom_python_logger import build_logger, json_pretty_format, yaml_pretty_format
100
103
 
101
- logger = get_logger(project_name='MyApp', utc=True, log_file=True)
104
+ logger = build_logger(project_name='MyApp', utc=True, log_file=True)
102
105
 
103
106
  logger.info(json_pretty_format({'foo': 'bar'}))
104
107
  logger.info(yaml_pretty_format({'foo': 'bar'}))
105
108
  ```
106
109
 
110
+ - use an existing logger (CustomLoggerAdapter) and set a custom name:
111
+ ```python
112
+ from custom_python_logger import get_logger
113
+
114
+ logger = get_logger('some-name')
115
+
116
+ logger.debug("This is a debug message.")
117
+ logger.info("This is an info message.")
118
+ logger.step("This is a step message.")
119
+ ```
120
+
107
121
  ---
108
122
 
109
123
  ## 🤝 Contributing
@@ -12,4 +12,6 @@ custom_python_logger.egg-info/SOURCES.txt
12
12
  custom_python_logger.egg-info/dependency_links.txt
13
13
  custom_python_logger.egg-info/requires.txt
14
14
  custom_python_logger.egg-info/top_level.txt
15
- tests/test_logger.py
15
+ tests/test_logger.py
16
+ tests/test_logger_pytest.py
17
+ tests/test_usage_example_pytest.py
@@ -1,6 +1,6 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
- package_version = '1.0.11'
3
+ package_version = '2.0.0'
4
4
 
5
5
  package_name = 'custom-python-logger'
6
6
  package_description = 'A custom logger with color support and additional features.'
@@ -1,20 +1,20 @@
1
1
  import unittest
2
- from custom_python_logger import get_logger
2
+ from custom_python_logger import build_logger
3
3
 
4
4
 
5
5
  class TestLogger(unittest.TestCase):
6
6
  def test_logger_creation(self):
7
- logger = get_logger(project_name='TestProject')
7
+ logger = build_logger(project_name='TestProject')
8
8
  self.assertIsNotNone(logger)
9
9
  self.assertEqual(logger.name, 'root')
10
10
 
11
11
  def test_step_log(self):
12
- logger = get_logger(project_name='TestProject')
12
+ logger = build_logger(project_name='TestProject')
13
13
  logger.step('Testing step log')
14
14
  self.assertTrue(True) # You can add more specific checks for actual logging output
15
15
 
16
16
  def test_exception_log(self):
17
- logger = get_logger(project_name='TestProject')
17
+ logger = build_logger(project_name='TestProject')
18
18
  try:
19
19
  raise ValueError("Test exception")
20
20
  except ValueError as e:
@@ -0,0 +1,126 @@
1
+ import logging
2
+ import os
3
+ import tempfile
4
+ import time
5
+ from datetime import timezone
6
+
7
+ import pytest
8
+
9
+ from custom_python_logger import (
10
+ CustomLoggerAdapter,
11
+ build_logger,
12
+ json_pretty_format,
13
+ yaml_pretty_format,
14
+ )
15
+
16
+
17
+ @pytest.fixture
18
+ def temp_log_file():
19
+ with tempfile.NamedTemporaryFile(delete=False) as f:
20
+ yield f.name
21
+ os.remove(f.name)
22
+
23
+
24
+ def test_logger_creation():
25
+ logger = build_logger(project_name="PytestTest")
26
+ assert logger is not None
27
+ assert isinstance(logger, CustomLoggerAdapter)
28
+ assert hasattr(logger, "step")
29
+ assert hasattr(logger, "exception")
30
+
31
+
32
+ def test_step_log(caplog):
33
+ logger = build_logger(project_name="PytestTest", console_output=False)
34
+ if not isinstance(logger, CustomLoggerAdapter):
35
+ raise AssertionError("Logger is not a CustomLoggerAdapter")
36
+ # Attach caplog.handler
37
+ logging.getLogger().addHandler(caplog.handler)
38
+ with caplog.at_level(logging.INFO):
39
+ logger.step("Step message")
40
+ assert any("Step message" in m for m in caplog.messages)
41
+ assert any("STEP" in r.levelname for r in caplog.records)
42
+
43
+
44
+ def test_step_log_2(caplog):
45
+ logger = build_logger(project_name="TestProject", console_output=False)
46
+ if not isinstance(logger, CustomLoggerAdapter):
47
+ raise AssertionError("Logger is not a CustomLoggerAdapter")
48
+ logging.getLogger().addHandler(caplog.handler)
49
+ with caplog.at_level(logging.INFO):
50
+ logger.step("Testing step log")
51
+ assert any("Testing step log" in m for m in caplog.messages)
52
+ assert any("STEP" in r.levelname for r in caplog.records)
53
+
54
+
55
+ def test_exception_log(caplog):
56
+ logger = build_logger(project_name="PytestTest", console_output=False)
57
+ logging.getLogger().addHandler(caplog.handler)
58
+ with caplog.at_level(logging.ERROR):
59
+ try:
60
+ raise RuntimeError("fail")
61
+ except RuntimeError:
62
+ logger.exception("Exception message")
63
+ assert any("Exception message" in m for m in caplog.messages)
64
+ assert any("EXCEPTION" in r.levelname for r in caplog.records)
65
+
66
+
67
+ def test_exception_log_2(caplog):
68
+ logger = build_logger(project_name="TestProject", console_output=False)
69
+ logging.getLogger().addHandler(caplog.handler)
70
+ with caplog.at_level(logging.ERROR):
71
+ try:
72
+ raise ValueError("Test exception")
73
+ except ValueError as e:
74
+ logger.exception(f"Exception occurred: {e}")
75
+ assert any("Exception occurred: Test exception" in m for m in caplog.messages)
76
+ assert any("EXCEPTION" in r.levelname for r in caplog.records)
77
+
78
+
79
+ def test_log_to_file(temp_log_file):
80
+ logger = build_logger(
81
+ project_name="FileTest", log_file=True, log_file_path=temp_log_file
82
+ )
83
+ logger.info("File log message")
84
+ time.sleep(0.1)
85
+ with open(temp_log_file) as f:
86
+ content = f.read()
87
+ assert "File log message" in content
88
+
89
+
90
+ def test_utc_logging(temp_log_file):
91
+ logger = build_logger(
92
+ project_name="UTCTest", log_file=True, log_file_path=temp_log_file, utc=True
93
+ )
94
+ logger.info("UTC log message")
95
+ time.sleep(0.1)
96
+ with open(temp_log_file) as f:
97
+ content = f.read()
98
+ assert "UTC log message" in content
99
+ # Check for a year in UTC (should be close to now)
100
+ import datetime
101
+
102
+ now_utc = datetime.datetime.now(tz=timezone.utc).strftime("%Y")
103
+ assert now_utc in content
104
+
105
+
106
+ def test_extra_context(caplog):
107
+ logger = build_logger(
108
+ project_name="ExtraTest", extra={"user": "pytest"}, console_output=False
109
+ )
110
+ logging.getLogger().addHandler(caplog.handler)
111
+ with caplog.at_level(logging.INFO):
112
+ logger.info("With extra")
113
+ assert any("With extra" in m for m in caplog.messages)
114
+ # The extra field is not in the default format, but test that logger works with extra
115
+
116
+
117
+ def test_json_pretty_format():
118
+ data = {"a": 1, "b": 2}
119
+ result = json_pretty_format(data)
120
+ assert "{" in result and "a" in result and "b" in result
121
+
122
+
123
+ def test_yaml_pretty_format():
124
+ data = {"a": 1, "b": 2}
125
+ result = yaml_pretty_format(data)
126
+ assert "a:" in result and "b:" in result
@@ -0,0 +1,8 @@
1
+ from custom_python_logger.usage_example import main
2
+
3
+
4
+ def test_usage_example_runs(monkeypatch):
5
+ # Patch print and time.sleep to avoid side effects
6
+ monkeypatch.setattr("builtins.print", lambda *a, **k: None)
7
+ monkeypatch.setattr("time.sleep", lambda x: None)
8
+ main() # Should not raise
@@ -1,10 +0,0 @@
1
- from custom_python_logger.logger import (
2
- get_logger, CustomLoggerAdapter, json_pretty_format, yaml_pretty_format
3
- )
4
-
5
- __all__ = [
6
- "get_logger",
7
- "CustomLoggerAdapter",
8
- "json_pretty_format",
9
- "yaml_pretty_format"
10
- ]