liblogging 0.1__py3-none-any.whl

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.
liblogging/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from .logger import *
liblogging/logger.py ADDED
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env python3
2
+
3
+ __author__ = "xi"
4
+ __all__ = [
5
+ "get_log_context",
6
+ "log_request",
7
+ "Logger",
8
+ "logger",
9
+ ]
10
+
11
+ import functools
12
+ import inspect
13
+ import json
14
+ import logging
15
+ import os
16
+ import sys
17
+ import threading
18
+ from contextvars import ContextVar
19
+ from datetime import datetime
20
+ from logging import Formatter, Handler, NOTSET
21
+ from logging.handlers import RotatingFileHandler
22
+ from typing import Dict, List, Mapping, Optional
23
+
24
+ try:
25
+ from tqdm import tqdm
26
+
27
+
28
+ class TqdmHandler(Handler):
29
+
30
+ def __init__(self, stream, level=NOTSET):
31
+ super().__init__(level)
32
+ self.stream = stream
33
+
34
+ def emit(self, record):
35
+ # noinspection PyBroadException
36
+ try:
37
+ msg = self.format(record)
38
+ tqdm.write(msg, file=self.stream)
39
+ self.flush()
40
+ except RecursionError:
41
+ raise
42
+ except Exception:
43
+ self.handleError(record)
44
+
45
+
46
+ StreamHandler = TqdmHandler
47
+ except ImportError:
48
+ tqdm = None
49
+ from logging import StreamHandler
50
+
51
+
52
+ class ThreadCoroutineLocal(threading.local):
53
+
54
+ def __init__(self):
55
+ super().__init__()
56
+ self._co_local = ContextVar[Optional[Dict]]("_co_local", default=None)
57
+
58
+ @property
59
+ def co_local(self):
60
+ co_local = self._co_local.get()
61
+ if co_local is None:
62
+ co_local = {}
63
+ self._co_local.set(co_local)
64
+ return co_local
65
+
66
+
67
+ thread_local = ThreadCoroutineLocal()
68
+
69
+
70
+ def get_log_context():
71
+ return thread_local.co_local
72
+
73
+
74
+ def log_request(fields=("trace_id", "request_id")):
75
+ def decorator(fn):
76
+ if not inspect.iscoroutinefunction(fn):
77
+ @functools.wraps(fn)
78
+ def _wrapper(*args, **kwargs):
79
+ log_context = thread_local.co_local
80
+ log_context.clear()
81
+ for field, value in _find_log_items(fields, args, kwargs):
82
+ log_context[field] = value
83
+ return fn(*args, **kwargs)
84
+ else:
85
+ @functools.wraps(fn)
86
+ async def _wrapper(*args, **kwargs):
87
+ log_context = thread_local.co_local
88
+ log_context.clear()
89
+ for field, value in _find_log_items(fields, args, kwargs):
90
+ log_context[field] = value
91
+ return await fn(*args, **kwargs)
92
+
93
+ return _wrapper
94
+
95
+ return decorator
96
+
97
+
98
+ def _find_log_items(fields: List[str], args: tuple, kwargs: dict):
99
+ args = [*args, *kwargs.values()]
100
+ for field in fields:
101
+ if field in kwargs:
102
+ yield field, kwargs[field]
103
+ else:
104
+ for arg in args:
105
+ try:
106
+ yield field, getattr(arg, field)
107
+ break
108
+ except AttributeError:
109
+ pass
110
+
111
+
112
+ class JSONFormatter(Formatter):
113
+
114
+ def format(self, record):
115
+ context: dict = thread_local.co_local
116
+
117
+ create_time = datetime.strptime(self.formatTime(record), "%Y-%m-%d %H:%M:%S,%f")
118
+ message = record.getMessage()
119
+ extra_message = {}
120
+ if isinstance(message, Mapping) and "message" in message:
121
+ extra_message = {**message}
122
+ message = extra_message["message"]
123
+ del extra_message["message"]
124
+
125
+ log_data = {
126
+ # "uid": uid,
127
+ # "session_id": session_id,
128
+ # "turn": turn,
129
+ "time": create_time.strftime("%Y-%m-%d %H:%M:%S"),
130
+ "level": record.levelname,
131
+ "trace_id": context.get("trace_id", None),
132
+ "code": f"{record.filename}:{record.lineno}:{record.funcName}",
133
+ # "message_source": getattr(record, "message_source", "planning_service"), # 控制不同源
134
+ # "message_type": getattr(record, "message_type", "common"), # 控制不同log类型
135
+ # "data": getattr(record, "data", {}),
136
+ "message": message,
137
+ **extra_message
138
+ }
139
+
140
+ output_log = json.dumps(log_data, ensure_ascii=False)
141
+ return output_log
142
+
143
+
144
+ class Logger(logging.Logger):
145
+
146
+ def __init__(
147
+ self,
148
+ name: str,
149
+ level: int = logging.INFO,
150
+ to_console: bool = True,
151
+ log_file: str = None,
152
+ max_size: int = 1024 * 1024 * 10,
153
+ backup_count: int = 3,
154
+ formatter: Formatter = JSONFormatter(),
155
+ ):
156
+ super().__init__(name, level)
157
+ self.propagate = False
158
+ self.warning_once = functools.lru_cache(self.warning)
159
+
160
+ if log_file:
161
+ log_dir = os.path.dirname(log_file)
162
+ if log_dir and not os.path.exists(log_dir):
163
+ os.makedirs(log_dir)
164
+ file_handler = RotatingFileHandler(log_file, maxBytes=max_size, backupCount=backup_count)
165
+ file_handler.setLevel(level)
166
+ file_handler.setFormatter(formatter)
167
+ self.addHandler(file_handler)
168
+
169
+ if to_console:
170
+ console_handler = StreamHandler(stream=sys.stdout)
171
+ console_handler.setLevel(level)
172
+ console_handler.setFormatter(formatter)
173
+ self.addHandler(console_handler)
174
+
175
+ def turn_start(self):
176
+ turn_id = thread_local.co_local.get("turn_id", "?")
177
+ self._log(logging.INFO, f"TurnStart[{turn_id}]", ())
178
+
179
+ def turn_end(self):
180
+ turn_id = thread_local.co_local.get("turn_id", "?")
181
+ self._log(logging.INFO, f"TurnEnd[{turn_id}]", ())
182
+
183
+
184
+ logger = Logger("libentry.logger")
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.1
2
+ Name: liblogging
3
+ Version: 0.1
4
+ Summary: Utilities for logging and sending logs.
5
+ Home-page: https://github.com/XoriieInpottn/liblogging
6
+ Author: xi
7
+ Author-email: gylv@mail.ustc.edu.cn
8
+ License: Apache-2.0 license
9
+ Platform: any
10
+ Classifier: Programming Language :: Python :: 3
11
+ Description-Content-Type: text/markdown
12
+
13
+ # liblogger
14
+
15
+
@@ -0,0 +1,7 @@
1
+ liblogging/__init__.py,sha256=Glf_NNarPLzBbAGbQ6vu1_owbu3KhQWHDgGdp9MR2Yo,46
2
+ liblogging/logger.py,sha256=H69IEAuElYmaG_YNRDfAdYnDlb514wc7KjIbYsPsOhA,5457
3
+ liblogging-0.1.dist-info/METADATA,sha256=YoZcocw8IRi0GJhcGDI9xJ6sz2vKRmfyOrhYaP9q2b8,348
4
+ liblogging-0.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
5
+ liblogging-0.1.dist-info/top_level.txt,sha256=u2OA7KVQrL0NSCSl8YTLmyEN5eZjczZTN9JPx0IUCAw,11
6
+ liblogging-0.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
7
+ liblogging-0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.45.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ liblogging
@@ -0,0 +1 @@
1
+