l4py 0.0.1__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.
l4py-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 roymanigley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
l4py-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.1
2
+ Name: l4py
3
+ Version: 0.0.1
4
+ Home-page: https://github.com/roymanigley/l4py
5
+ Author: Roy Manigley
6
+ Author-email: roy.manigley@gmail.com
7
+ License: MIT
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+
16
+ # l4py
17
+ ![Unit-Tests](https://github.com/roymanigley/l4py/actions/workflows/test.yml/badge.svg)
18
+ ![Published Python Package](https://github.com/roymanigley/l4py/actions/workflows/publish.yml/badge.svg)
19
+
20
+ ## Installation
21
+ ```
22
+ pip install l4py
23
+ ```
24
+ or from Github:
25
+ ```
26
+ git clone https://github.com/roymanigley/l4py.git
27
+ cd l4py
28
+ pip install -r requirements.txt
29
+ python setup.py install
30
+ ```
31
+ ## Usage
32
+
33
+ ```python
34
+ from l4py import Builder
35
+ ```
l4py-0.0.1/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # l4py
2
+ ![Unit-Tests](https://github.com/roymanigley/l4py/actions/workflows/test.yml/badge.svg)
3
+ ![Published Python Package](https://github.com/roymanigley/l4py/actions/workflows/publish.yml/badge.svg)
4
+
5
+ ## Installation
6
+ ```
7
+ pip install l4py
8
+ ```
9
+ or from Github:
10
+ ```
11
+ git clone https://github.com/roymanigley/l4py.git
12
+ cd l4py
13
+ pip install -r requirements.txt
14
+ python setup.py install
15
+ ```
16
+ ## Usage
17
+
18
+ ```python
19
+ from l4py import Builder
20
+ ```
@@ -0,0 +1,2 @@
1
+ from .builder import LogBuilder as Builder
2
+ from .builder import DjangoLogBuilder as DjangoBuilder
@@ -0,0 +1,198 @@
1
+ import logging
2
+ import os
3
+ from logging.handlers import RotatingFileHandler
4
+
5
+ from l4py import utils
6
+ from l4py.formatters import TextFormatter, JsonFormatter
7
+
8
+
9
+ class LogBuilder:
10
+ __text_formatter = TextFormatter()
11
+ __json_formatter = JsonFormatter()
12
+
13
+ __console_format = None
14
+ __console_json = False
15
+ __console_level = None
16
+
17
+ __file = None
18
+ __file_format = None
19
+ __file_json = True
20
+ __file_level = None
21
+ __file_max_size = 10 * 1024 * 1024 # 10 MB (default)
22
+ __file_max_count = 5 # Default 5 backup files
23
+
24
+ def text_formatter(self, text_formatter: logging.Formatter) -> 'LogBuilder':
25
+ self.__text_formatter = text_formatter
26
+ return self
27
+
28
+ def json_formatter(self, json_formatter: logging.Formatter) -> 'LogBuilder':
29
+ self.__json_formatter = json_formatter
30
+ return self
31
+
32
+ def console_format(self, format_str: str) -> 'LogBuilder':
33
+ self.__console_format = format_str
34
+ return self
35
+
36
+ def console_json(self, value: bool) -> 'LogBuilder':
37
+ self.__console_json = value
38
+ return self
39
+
40
+ def console_level(self, level: int) -> 'LogBuilder':
41
+ self.__console_level = level
42
+ return self
43
+
44
+ def file(self, file_name: str) -> 'LogBuilder':
45
+ self.__file = file_name
46
+ return self
47
+
48
+ def file_format(self, format_str: str) -> 'LogBuilder':
49
+ self.__file_format = format_str
50
+ return self
51
+
52
+ def file_json(self, value: bool) -> 'LogBuilder':
53
+ self.__file_json = value
54
+ return self
55
+
56
+ def file_level(self, level: int) -> 'LogBuilder':
57
+ self.__file_level = level
58
+ return self
59
+
60
+ def file_max_size_mb(self, size_in_mb: int) -> 'LogBuilder':
61
+ self.__file_max_size = size_in_mb * 1024 * 1024
62
+ return self
63
+
64
+ def file_max_count(self, count: int) -> 'LogBuilder':
65
+ self.__file_max_count = count
66
+ return self
67
+
68
+ def build(self, logger_name: str = 'python-app') -> logging.Logger:
69
+ logger = logging.getLogger(logger_name)
70
+ logger.setLevel(logging.DEBUG)
71
+
72
+ console_handler = self.__build_console_handler(logger_name)
73
+ logger.addHandler(console_handler)
74
+
75
+ if self.__file:
76
+ file_handler = self.__build_file_handler(logger_name)
77
+ logger.addHandler(file_handler)
78
+
79
+ return logger
80
+
81
+ def __build_console_handler(self, logger_name: str) -> logging.Handler:
82
+ console_handler = logging.StreamHandler()
83
+ log_level = self.__console_level
84
+ if log_level is None:
85
+ log_level = utils.get_log_level(logger_name)
86
+ console_handler.setLevel(log_level)
87
+ if self.__console_format:
88
+ console_formatter = logging.Formatter(self.__console_format)
89
+ elif self.__console_json:
90
+ console_formatter = self.__json_formatter
91
+ else:
92
+ console_formatter = self.__text_formatter
93
+ console_handler.setFormatter(console_formatter)
94
+ return console_handler
95
+
96
+ def __build_file_handler(self, logger_name: str) -> logging.Handler:
97
+ file_handler = RotatingFileHandler(
98
+ self.__file,
99
+ maxBytes=self.__file_max_size,
100
+ backupCount=self.__file_max_count
101
+ )
102
+ log_level = self.__file_level
103
+ if log_level is None:
104
+ log_level = utils.get_log_level(logger_name)
105
+ file_handler.setLevel(log_level)
106
+ if self.__file_format:
107
+ file_formatter = logging.Formatter(self.__file_format)
108
+ elif self.__file_json:
109
+ file_formatter = self.__json_formatter
110
+ else:
111
+ file_formatter = self.text_formatter
112
+ file_handler.setFormatter(file_formatter)
113
+ return file_handler
114
+
115
+
116
+ class DjangoLogBuilder:
117
+ __text_formatter = TextFormatter()
118
+ __json_formatter = JsonFormatter()
119
+
120
+ __console_json = False
121
+
122
+ __file = None
123
+ __file_json = True
124
+ __file_max_size = 10 * 1024 * 1024 # 10 MB (default)
125
+ __file_max_count = 5 # Default 5 backup files
126
+
127
+ def console_json(self, value: bool) -> 'DjangoLogBuilder':
128
+ self.__console_json = value
129
+ return self
130
+
131
+ def file(self, file_name: str) -> 'DjangoLogBuilder':
132
+ self.__file = file_name
133
+ return self
134
+
135
+ def file_json(self, value: bool) -> 'DjangoLogBuilder':
136
+ self.__file_json = value
137
+ return self
138
+
139
+ def file_max_size_mb(self, size_in_mb: int) -> 'DjangoLogBuilder':
140
+ self.__file_max_size = size_in_mb * 1024 * 1024
141
+ return self
142
+
143
+ def file_max_count(self, count: int) -> 'DjangoLogBuilder':
144
+ self.__file_max_count = count
145
+ return self
146
+
147
+ def build_config_4_django(self, django_log_level=None, show_sql=False) -> dict:
148
+ django_log_level = django_log_level if django_log_level else utils.get_log_level_root()
149
+ django_config = {
150
+ 'version': 1,
151
+ 'disable_existing_loggers': False,
152
+ 'filters': {
153
+ 'trace_id': {
154
+ '()': 'kydo.logging_helpers.TraceIDFilter',
155
+ },
156
+ 'stack_trace': {
157
+ '()': 'kydo.logging_helpers.StackTraceFilter',
158
+ },
159
+ },
160
+ 'handlers': {
161
+ 'console': {
162
+ 'class': 'logging.StreamHandler',
163
+ 'filters': ['trace_id', 'stack_trace'],
164
+ 'formatter': 'default',
165
+ },
166
+ 'file': {
167
+ 'class': 'logging.handlers.RotatingFileHandler',
168
+ 'filename': self.__file,
169
+ 'maxBytes': self.__file_max_size,
170
+ 'backupCount': self.__file_max_count,
171
+ 'filters': ['trace_id', 'stack_trace'],
172
+ 'formatter': 'json',
173
+ },
174
+ },
175
+ 'root': {
176
+ 'level': utils.get_log_level_root(),
177
+ },
178
+ 'loggers': {
179
+ 'django': {
180
+ 'level': django_log_level,
181
+ 'propagate': False,
182
+ },
183
+ 'django.db.backends': {
184
+ 'handlers': ['console', 'file'],
185
+ 'level': 'DEBUG' if show_sql else django_log_level,
186
+ 'propagate': False,
187
+ },
188
+ },
189
+ 'formatters': {
190
+ 'json': {
191
+ '()': f'{JsonFormatter.__module__}.{JsonFormatter.__name__}',
192
+ },
193
+ 'default': {
194
+ '()': f'{TextFormatter.__module__}.{TextFormatter.__name__}',
195
+ },
196
+ },
197
+ }
198
+ return django_config
@@ -0,0 +1,55 @@
1
+ import json
2
+ import logging
3
+ from datetime import datetime
4
+
5
+ from l4py import utils
6
+
7
+
8
+ class FormatTimeMixin():
9
+ def formatTime(self, record, datefmt=None):
10
+ ct = datetime.fromtimestamp(record.created)
11
+ if datefmt:
12
+ return ct.strftime(datefmt)
13
+ else:
14
+ return ct.strftime("%Y-%m-%dT%H:%M:%S.") + f"{int(record.msecs):03d}"
15
+
16
+
17
+ class JsonFormatter(FormatTimeMixin, logging.Formatter):
18
+
19
+ def __init__(self, app_name=utils.get_app_name()):
20
+ super().__init__()
21
+ self.app_name = app_name
22
+
23
+ def format(self, record):
24
+ log_record = {
25
+ "timestamp": self.formatTime(record),
26
+ "app_name": self.app_name,
27
+ "logger_name": record.name,
28
+ "level": record.levelname,
29
+ "file_name": record.filename,
30
+ "line_number": record.lineno,
31
+ "function_name": record.funcName,
32
+ "message": record.msg,
33
+ }
34
+ return json.dumps(log_record)
35
+
36
+
37
+ class TextFormatter(FormatTimeMixin, logging.Formatter):
38
+
39
+ def __init__(self, app_name=utils.get_app_name()):
40
+ super().__init__()
41
+ self.app_name = app_name
42
+
43
+ def format(self, record):
44
+ log_record = {
45
+ "timestamp": self.formatTime(record),
46
+ "app_name": self.app_name,
47
+ "logger_name": record.name,
48
+ "level": record.levelname,
49
+ "file_name": record.filename,
50
+ "line_number": record.lineno,
51
+ "function_name": record.funcName,
52
+ "message": record.msg,
53
+ }
54
+ return '{timestamp} [{level:<8}] {app_name} {file_name}:{line_number} {function_name}: {message}'.format(
55
+ **log_record)
@@ -0,0 +1,17 @@
1
+ from .builder import LogBuilder
2
+
3
+ if __name__ == '__main__':
4
+ class TestLogger:
5
+
6
+ logger = LogBuilder()\
7
+ .file('test.log')\
8
+ .build(__name__)
9
+
10
+ def test(self):
11
+ self.logger.debug("This is a debug message")
12
+ self.logger.info("This is an info message")
13
+ self.logger.warning("This is a warning message")
14
+ self.logger.error("This is an error message")
15
+ self.logger.critical("This is a critical message")
16
+
17
+ TestLogger().test()
@@ -0,0 +1,49 @@
1
+ import logging
2
+ import os
3
+
4
+ _LOG_LEVEL_PREFIX = 'PYTHON_LOG_LEVEL_'
5
+ _LOG_LEVEL_ROOT_KEY = f'{_LOG_LEVEL_PREFIX}ROOT'
6
+ _LOG_LEVEL_LOGGER_KEY_FORMAT = f'{_LOG_LEVEL_PREFIX}{{}}'
7
+
8
+ logging_env_vars = [
9
+ {'key': key, 'value': value}
10
+ for key, value in os.environ.items()
11
+ if key.startswith(_LOG_LEVEL_PREFIX)
12
+ ]
13
+ logging_env_vars.sort(key=lambda item: item['key'])
14
+
15
+
16
+ def get_app_name() -> str:
17
+ return os.environ.get('PYTHON_APP_NAME', 'python-app')
18
+
19
+
20
+ def get_log_level_root() -> str:
21
+ return os.environ.get(_LOG_LEVEL_ROOT_KEY, logging.INFO)
22
+
23
+
24
+ def get_log_level(logger_name: str) -> str:
25
+ log_level = get_log_level_root()
26
+ for key, value in [(v['key'], v['value']) for v in logging_env_vars]:
27
+ if key.startswith(_LOG_LEVEL_PREFIX):
28
+ logger_name_for_level = _LOG_LEVEL_LOGGER_KEY_FORMAT.format(logger_name)
29
+ if key == logger_name_for_level:
30
+ return value
31
+ elif (logger_name_for_level).startswith(key + '.'):
32
+ log_level = value
33
+ return log_level
34
+
35
+
36
+ if __name__ == '__main__':
37
+ logger_name = 'logger.name'
38
+ os.environ.setdefault(f'{_LOG_LEVEL_PREFIX}logger', 'WARN')
39
+ os.environ.setdefault(f'{_LOG_LEVEL_PREFIX}logger.name', 'INFO')
40
+ os.environ.setdefault(f'{_LOG_LEVEL_PREFIX}logger.name_not', 'DEBUG')
41
+ os.environ.setdefault(f'{_LOG_LEVEL_PREFIX}logger.name_n', 'FATAL')
42
+
43
+ print(get_log_level('logger'))
44
+ print(get_log_level('logger.name'))
45
+ print(get_log_level('logger.name_not'))
46
+ print(get_log_level('logger.name_n'))
47
+ print(get_log_level('logger.name_naaaaa'))
48
+
49
+ print(logging.getLevelNamesMapping())
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.1
2
+ Name: l4py
3
+ Version: 0.0.1
4
+ Home-page: https://github.com/roymanigley/l4py
5
+ Author: Roy Manigley
6
+ Author-email: roy.manigley@gmail.com
7
+ License: MIT
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+
16
+ # l4py
17
+ ![Unit-Tests](https://github.com/roymanigley/l4py/actions/workflows/test.yml/badge.svg)
18
+ ![Published Python Package](https://github.com/roymanigley/l4py/actions/workflows/publish.yml/badge.svg)
19
+
20
+ ## Installation
21
+ ```
22
+ pip install l4py
23
+ ```
24
+ or from Github:
25
+ ```
26
+ git clone https://github.com/roymanigley/l4py.git
27
+ cd l4py
28
+ pip install -r requirements.txt
29
+ python setup.py install
30
+ ```
31
+ ## Usage
32
+
33
+ ```python
34
+ from l4py import Builder
35
+ ```
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ setup.py
4
+ l4py/__init__.py
5
+ l4py/builder.py
6
+ l4py/formatters.py
7
+ l4py/l4py.py
8
+ l4py/utils.py
9
+ l4py.egg-info/PKG-INFO
10
+ l4py.egg-info/SOURCES.txt
11
+ l4py.egg-info/dependency_links.txt
12
+ l4py.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ l4py
l4py-0.0.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
l4py-0.0.1/setup.py ADDED
@@ -0,0 +1,25 @@
1
+ from setuptools import setup
2
+
3
+ long_description = open('README.md', "rt").read()
4
+
5
+ setup(
6
+ name='l4py',
7
+ version='0.0.1',
8
+ description='',
9
+ long_description=long_description,
10
+ long_description_content_type='text/markdown',
11
+ url='https://github.com/roymanigley/l4py',
12
+ author='Roy Manigley',
13
+ author_email='roy.manigley@gmail.com',
14
+ license='MIT',
15
+ packages=['l4py'],
16
+ install_requires=[],
17
+
18
+ classifiers=[
19
+ 'Development Status :: 5 - Production/Stable',
20
+ 'Intended Audience :: Developers',
21
+ 'License :: OSI Approved :: MIT License',
22
+ 'Operating System :: POSIX :: Linux',
23
+ 'Programming Language :: Python :: 3.11',
24
+ ],
25
+ )