izihawa-loglib 1.1.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.
@@ -0,0 +1,20 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: izihawa_loglib
|
3
|
+
Version: 1.1.1
|
4
|
+
Summary: Izihawa log utilities
|
5
|
+
Author: Pasha Podolsky
|
6
|
+
Author-email: ppodolsky@me.com
|
7
|
+
Requires-Python: >=3.8.1,<3.13
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
13
|
+
Requires-Dist: confuse (>=2.0.1,<3.0.0)
|
14
|
+
Requires-Dist: izihawa-types (>=0.1.4,<0.2.0)
|
15
|
+
Requires-Dist: izihawa-utils (>=1.2.1,<2.0.0)
|
16
|
+
Requires-Dist: orjson (>=3.9.10,<4.0.0)
|
17
|
+
Description-Content-Type: text/markdown
|
18
|
+
|
19
|
+
# izihawa_netlib
|
20
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
# izihawa_netlib
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import logging
|
2
|
+
import logging.config
|
3
|
+
import sys
|
4
|
+
|
5
|
+
from izihawa_utils.exceptions import BaseError
|
6
|
+
from izihawa_utils.file import mkdir_p
|
7
|
+
|
8
|
+
from .handlers import QueueHandler
|
9
|
+
|
10
|
+
|
11
|
+
def configure_logging(config: dict, make_path: bool = False, default_level=logging.INFO):
|
12
|
+
if config.get("application", {}).get("debug", False) or "logging" not in config:
|
13
|
+
logging.basicConfig(stream=sys.stdout, level=default_level)
|
14
|
+
else:
|
15
|
+
if make_path:
|
16
|
+
mkdir_p(config["log_path"])
|
17
|
+
logging.config.dictConfig(config["logging"])
|
18
|
+
|
19
|
+
|
20
|
+
def error_log(e, level=logging.ERROR, **fields):
|
21
|
+
level = getattr(e, "level", level)
|
22
|
+
if isinstance(e, BaseError):
|
23
|
+
e = e.as_internal_dict()
|
24
|
+
e.update(fields)
|
25
|
+
elif fields:
|
26
|
+
e = {"error": repr(e), **fields}
|
27
|
+
logging.getLogger("error").log(msg=str(e), level=level)
|
28
|
+
|
29
|
+
|
30
|
+
__all__ = [
|
31
|
+
"QueueHandler",
|
32
|
+
"configure_logging",
|
33
|
+
"error_log",
|
34
|
+
]
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import dataclasses
|
2
|
+
import datetime
|
3
|
+
import logging
|
4
|
+
import os
|
5
|
+
import pprint
|
6
|
+
import time
|
7
|
+
import traceback
|
8
|
+
import typing
|
9
|
+
|
10
|
+
import orjson as json
|
11
|
+
from izihawa_utils.exceptions import BaseError
|
12
|
+
|
13
|
+
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
|
14
|
+
|
15
|
+
|
16
|
+
class BaseFormatter(logging.Formatter):
|
17
|
+
def _prepare(self, record):
|
18
|
+
if isinstance(record.msg, BaseError):
|
19
|
+
return record.msg.as_internal_dict()
|
20
|
+
elif isinstance(record.msg, typing.Dict) or dataclasses.is_dataclass(
|
21
|
+
record.msg
|
22
|
+
):
|
23
|
+
return record.msg
|
24
|
+
else:
|
25
|
+
return dict(message=super().format(record))
|
26
|
+
|
27
|
+
def format(self, record):
|
28
|
+
log_record = self._prepare(record)
|
29
|
+
return json.dumps(log_record).decode()
|
30
|
+
|
31
|
+
|
32
|
+
class DefaultHttpFormatter(BaseFormatter):
|
33
|
+
def _prepare(self, record):
|
34
|
+
log_record = super()._prepare(record)
|
35
|
+
|
36
|
+
timestamp = time.time()
|
37
|
+
formatted_datetime = datetime.datetime.fromtimestamp(timestamp).strftime(
|
38
|
+
DATETIME_FORMAT
|
39
|
+
)
|
40
|
+
user_ip = getattr(record, "user_ip", None)
|
41
|
+
request_id = getattr(record, "request_id", None)
|
42
|
+
method = getattr(record, "method", None)
|
43
|
+
path = getattr(record, "path", None)
|
44
|
+
|
45
|
+
log_record.update(
|
46
|
+
unixtime=int(timestamp),
|
47
|
+
timestamp=int(timestamp * 1_000_000),
|
48
|
+
datetime=formatted_datetime,
|
49
|
+
process=os.getpid(),
|
50
|
+
)
|
51
|
+
|
52
|
+
if user_ip:
|
53
|
+
log_record["user_ip"] = user_ip
|
54
|
+
if request_id:
|
55
|
+
log_record["request_id"] = request_id
|
56
|
+
if method:
|
57
|
+
log_record["method"] = method
|
58
|
+
if path:
|
59
|
+
log_record["path"] = path
|
60
|
+
|
61
|
+
return log_record
|
62
|
+
|
63
|
+
def format(self, record):
|
64
|
+
log_record = self._prepare(record)
|
65
|
+
return json.dumps(log_record).decode()
|
66
|
+
|
67
|
+
|
68
|
+
class DefaultFormatter(BaseFormatter):
|
69
|
+
def _prepare(self, record):
|
70
|
+
log_record = super()._prepare(record)
|
71
|
+
|
72
|
+
timestamp = time.time()
|
73
|
+
formatted_datetime = datetime.datetime.fromtimestamp(timestamp).strftime(
|
74
|
+
DATETIME_FORMAT
|
75
|
+
)
|
76
|
+
|
77
|
+
log_record.update(
|
78
|
+
unixtime=int(timestamp),
|
79
|
+
timestamp=int(timestamp * 1_000_000),
|
80
|
+
datetime=formatted_datetime,
|
81
|
+
process=os.getpid(),
|
82
|
+
)
|
83
|
+
return log_record
|
84
|
+
|
85
|
+
def format(self, record):
|
86
|
+
log_record = self._prepare(record)
|
87
|
+
return json.dumps(log_record).decode()
|
88
|
+
|
89
|
+
|
90
|
+
class TracebackFormatter(DefaultFormatter):
|
91
|
+
def format(self, record):
|
92
|
+
log_record = self._prepare(record)
|
93
|
+
value = pprint.pformat(log_record, indent=2)
|
94
|
+
if traceback.sys.exc_info()[0] is not None:
|
95
|
+
value += "\n" + traceback.format_exc()
|
96
|
+
return value
|
97
|
+
|
98
|
+
|
99
|
+
default_formatter = DefaultFormatter()
|
100
|
+
default_traceback_formatter = TracebackFormatter()
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import logging.handlers
|
2
|
+
import os
|
3
|
+
import queue
|
4
|
+
|
5
|
+
from izihawa_types.var import varstr
|
6
|
+
|
7
|
+
|
8
|
+
class QueueHandler(logging.handlers.QueueHandler):
|
9
|
+
def __init__(self, *handlers):
|
10
|
+
self._queue = queue.Queue(-1)
|
11
|
+
self._listener = logging.handlers.QueueListener(
|
12
|
+
self._queue, *handlers, respect_handler_level=True
|
13
|
+
)
|
14
|
+
self.setLevel("INFO")
|
15
|
+
|
16
|
+
super().__init__(self._queue)
|
17
|
+
self._listener.start()
|
18
|
+
|
19
|
+
def stop(self):
|
20
|
+
self._listener.stop()
|
21
|
+
|
22
|
+
def prepare(self, record):
|
23
|
+
return record
|
24
|
+
|
25
|
+
|
26
|
+
class BaseFileHandler(logging.handlers.WatchedFileHandler):
|
27
|
+
def _open(self):
|
28
|
+
file = super()._open()
|
29
|
+
os.chmod(self.baseFilename, 0o644)
|
30
|
+
return file
|
31
|
+
|
32
|
+
|
33
|
+
class BaseBinaryFileHandler(BaseFileHandler):
|
34
|
+
def __init__(self, *args, **kwargs):
|
35
|
+
super().__init__(*args, **kwargs, mode="ab+")
|
36
|
+
|
37
|
+
def emit(self, record):
|
38
|
+
try:
|
39
|
+
self.stream.write(varstr(record.msg))
|
40
|
+
self.flush()
|
41
|
+
except RecursionError:
|
42
|
+
raise
|
43
|
+
except Exception:
|
44
|
+
self.handleError(record)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
[tool.poetry]
|
2
|
+
name = "izihawa_loglib"
|
3
|
+
version = "1.1.1"
|
4
|
+
description = "Izihawa log utilities"
|
5
|
+
authors = ["Pasha Podolsky <ppodolsky@me.com>"]
|
6
|
+
readme = "README.md"
|
7
|
+
packages = [{include = "izihawa_loglib"}]
|
8
|
+
|
9
|
+
|
10
|
+
[tool.poetry.dependencies]
|
11
|
+
python = "^3.8.1,<3.13"
|
12
|
+
confuse = "^2.0.1"
|
13
|
+
izihawa-types = "^0.1.4"
|
14
|
+
izihawa-utils = "^1.2.1"
|
15
|
+
orjson = "^3.9.10"
|
16
|
+
|
17
|
+
|
18
|
+
[tool.poetry.group.dev.dependencies]
|
19
|
+
mypy = "~1.7.0"
|
20
|
+
pylint = "~3.0.0"
|
21
|
+
pyproject-flake8 = "~6.1.0"
|
22
|
+
twine = "~4.0.2"
|
23
|
+
|
24
|
+
|
25
|
+
[build-system]
|
26
|
+
requires = ["poetry-core"]
|
27
|
+
build-backend = "poetry.core.masonry.api"
|