mlog-util 0.1.3__tar.gz → 0.1.5__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.

Potentially problematic release.


This version of mlog-util might be problematic. Click here for more details.

@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: mlog-util
3
+ Version: 0.1.5
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: rich>=14.2.0
8
+ Requires-Dist: portalocker
@@ -0,0 +1,16 @@
1
+ [project]
2
+ name = "mlog-util"
3
+ version = "0.1.5"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "rich>=14.2.0",
9
+ "portalocker"
10
+ ]
11
+
12
+ [dependency-groups]
13
+ dev = [
14
+ "setuptools>=80.9.0",
15
+ "twine>=6.2.0",
16
+ ]
@@ -0,0 +1,108 @@
1
+ import logging
2
+ import threading
3
+ from rich.logging import RichHandler
4
+ from typing import Type, List, Optional
5
+
6
+ # from .handlers import MultiProcessSafeSizeRotatingHandler, MultiProcessSafeTimeRotatingHandler
7
+
8
+ class LogManager:
9
+ """
10
+ 一个线程安全的日志管理器,用于获取和配置具有 Rich 控制台输出的 Logger。
11
+ """
12
+ _logger_cache: dict[str, logging.Logger] = {}
13
+ _lock = threading.Lock()
14
+
15
+ @classmethod
16
+ def get_logger(
17
+ cls,
18
+ name: str,
19
+ log_file: Optional[str] = None,
20
+ add_console: bool = True,
21
+ level: int = logging.INFO,
22
+ custom_handlers: Optional[List[logging.Handler]] = None,
23
+ ) -> logging.Logger:
24
+ """
25
+ 获取或创建一个配置好的 logger。
26
+
27
+ 注意:Logger 实例按 name 缓存。重复调用会返回同一个实例,
28
+ 但会确保其配置(如 level 和 handlers)符合当前调用参数。
29
+
30
+ :param name: logger 名称。
31
+ :param log_file: 日志文件路径,如果为 None 则不写入文件。
32
+ :param add_console: 是否添加带 Rich 格式的控制台 Handler。
33
+ :param level: 日志级别。
34
+ :param custom_handlers: 自定义 Handler 列表。
35
+ """
36
+ with cls._lock:
37
+ # 1. 获取或创建 Logger 实例 (利用 logging 模块自身的缓存)
38
+ logger = logging.getLogger(name)
39
+
40
+ # 2. 确保基本配置
41
+ logger.setLevel(level)
42
+ logger.propagate = False
43
+
44
+ # 3. 配置控制台 Handler
45
+ if add_console and not any(isinstance(h, RichHandler) for h in logger.handlers):
46
+ console_handler = RichHandler(rich_tracebacks=True, show_time=False, show_path=False)
47
+ # 注意:RichHandler 默认有自己的时间格式,我们可以在 Formatter 中覆盖
48
+ console_formatter = logging.Formatter(
49
+ "[%(name)s - %(asctime)s] %(message)s",
50
+ datefmt="%Y-%m-%d %H:%M:%S"
51
+ )
52
+ console_handler.setFormatter(console_formatter)
53
+ logger.addHandler(console_handler)
54
+
55
+ # 4. 配置文件 Handler
56
+ if log_file and not any(isinstance(h, logging.FileHandler) for h in logger.handlers):
57
+ file_handler = logging.FileHandler(log_file, encoding="utf-8")
58
+ file_formatter = logging.Formatter(
59
+ "%(asctime)s | %(name)s | %(levelname)-8s | %(message)s",
60
+ datefmt="%Y-%m-%d %H:%M:%S"
61
+ )
62
+ file_handler.setFormatter(file_formatter)
63
+ logger.addHandler(file_handler)
64
+
65
+ # 5. 配置自定义 Handlers (修正了原代码的 Bug)
66
+ if custom_handlers:
67
+ # 为所有自定义 handlers 设置一个统一的格式
68
+ custom_formatter = logging.Formatter(
69
+ "%(asctime)s | %(name)s | %(levelname)-8s | %(message)s",
70
+ datefmt="%Y-%m-%d %H:%M:%S"
71
+ )
72
+ for handler in custom_handlers:
73
+ if handler not in logger.handlers:
74
+ handler.setFormatter(custom_formatter)
75
+ logger.addHandler(handler)
76
+
77
+ return logger
78
+
79
+
80
+ # 全局可用的 get_logger 函数(无需引用 LogManager)
81
+ def get_logger(
82
+ name: str=None,
83
+ log_file: Optional[str] = None,
84
+ add_console: bool = True,
85
+ level: int = logging.INFO,
86
+ custom_handlers: Optional[List[logging.Handler]] = None,
87
+ ):
88
+ """
89
+ 便捷函数:获取日志记录器,无需关心 LogManager 实例化。
90
+
91
+ 使用示例:
92
+ from log_manager import get_logger
93
+ logger = get_logger("my_module", log_file="app.log")
94
+ logger.info("Hello world")
95
+ """
96
+ if name is None:
97
+ name = "tmp_log"
98
+
99
+ return LogManager.get_logger(
100
+ name=name,
101
+ log_file=log_file,
102
+ add_console=add_console,
103
+ level=level,
104
+ custom_handlers=custom_handlers
105
+ )
106
+
107
+ # logger = LogManager().get_logger("tmp_log")
108
+
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: mlog-util
3
+ Version: 0.1.5
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: rich>=14.2.0
8
+ Requires-Dist: portalocker
@@ -0,0 +1,10 @@
1
+ pyproject.toml
2
+ src/mlog-util/__init__.py
3
+ src/mlog-util/handlers.py
4
+ src/mlog-util/log_manager.py
5
+ src/mlog_util.egg-info/PKG-INFO
6
+ src/mlog_util.egg-info/SOURCES.txt
7
+ src/mlog_util.egg-info/dependency_links.txt
8
+ src/mlog_util.egg-info/requires.txt
9
+ src/mlog_util.egg-info/top_level.txt
10
+ tests/test_mlog.py
@@ -0,0 +1,2 @@
1
+ rich>=14.2.0
2
+ portalocker
@@ -0,0 +1 @@
1
+ mlog-util
@@ -0,0 +1,37 @@
1
+ import time
2
+ import os
3
+ import mlog
4
+ from mlog import LogManager
5
+ from multiprocessing import Pool
6
+
7
+ log_file = "logs/a1.log"
8
+
9
+ log_manager = LogManager()
10
+ logger_a1 = log_manager.get_logger("a1", log_file=log_file, add_console=False)
11
+ # logger_a2 = log_manager.get_logger("a2", log_file=log_file, add_console=False)
12
+ # logger_a3 = log_manager.get_logger("a3", log_file=log_file, add_console=False)
13
+
14
+
15
+ # 测试 num 个 日志耗时
16
+ def test_speed_time(num = 500):
17
+ import time
18
+ _st = time.time()
19
+ for i in range(num):
20
+ logger_a1.info(i)
21
+ logger_a1.info(f"{num} --- {time.time() - _st}")
22
+
23
+ # 测试多进程
24
+ # 1000 个日志有没有
25
+ def test_logger(x):
26
+ _pid = os.getpid()
27
+ logger_a1.info(f"{_pid} -- {x}")
28
+
29
+
30
+ if __name__ == "__main__":
31
+ with open(log_file, "w") as f:
32
+ pass
33
+ with Pool(2) as pool:
34
+ pool.map(test_logger, range(0, 5000))
35
+
36
+
37
+
mlog_util-0.1.3/PKG-INFO DELETED
@@ -1,14 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: mlog_util
3
- Version: 0.1.3
4
- Summary: 自用日志库
5
- Classifier: Programming Language :: Python :: 3
6
- Classifier: License :: OSI Approved :: MIT License
7
- Classifier: Operating System :: OS Independent
8
- Requires-Python: >=3.6
9
- Requires-Dist: rich
10
- Requires-Dist: portalocker
11
- Dynamic: classifier
12
- Dynamic: requires-dist
13
- Dynamic: requires-python
14
- Dynamic: summary
@@ -1,116 +0,0 @@
1
- import logging
2
- import threading
3
- from rich.logging import RichHandler
4
- from typing import Type, List, Optional
5
-
6
- # from .handlers import MultiProcessSafeSizeRotatingHandler, MultiProcessSafeTimeRotatingHandler
7
-
8
- class LogManager:
9
- _logger_cache = {}
10
- _lock = threading.Lock() # 多线程安全
11
-
12
- @classmethod
13
- def get_logger(
14
- cls,
15
- name: str,
16
- logger_cls: Type[logging.Logger] = logging.Logger,
17
- log_file: str | None = None,
18
- add_console: bool = True,
19
- level: int = logging.INFO,
20
- custom_handlers: list[logging.Handler] | None = None,
21
- ) -> logging.Logger:
22
- """
23
- 获取或创建 logger。
24
-
25
- :param name: logger 名称
26
- :param logger_cls: logger 类
27
- :param log_file: 日志文件路径
28
- :param add_console: 是否添加控制台 RichHandler
29
- :param level: 日志级别
30
- :param custom_handlers: 自定义 Handler 列表
31
- """
32
- cache_key = (name, logger_cls)
33
- with cls._lock:
34
- if cache_key not in cls._logger_cache:
35
- # 创建 logger
36
- if logger_cls == logging.Logger:
37
- logger = logging.getLogger(name)
38
- else:
39
- logger = logger_cls(name)
40
-
41
- logger.setLevel(level)
42
- logger.propagate = False # 不向 root logger 冒泡
43
-
44
- # 添加控制台 handler
45
- if add_console:
46
- if not any(isinstance(h, RichHandler) for h in logger.handlers):
47
- console_handler = RichHandler(rich_tracebacks=True)
48
- console_formatter = logging.Formatter(
49
- "%(message)s [%(name)s - %(asctime)s]",
50
- datefmt="%Y-%m-%d %H:%M:%S"
51
- )
52
- console_handler.setFormatter(console_formatter)
53
- logger.addHandler(console_handler)
54
-
55
- # 添加文件 handler
56
- if log_file:
57
- if not any(isinstance(h, logging.FileHandler) for h in logger.handlers):
58
- # handler = MultiProcessSafeSizeRotatingHandler(log_file, maxBytes=10*200, backupCount=3)
59
- # file_handler = logging.FileHandler(log_file, encoding="utf-8")
60
-
61
- handler = logging.FileHandler(log_file, encoding="utf-8")
62
- file_formatter = logging.Formatter(
63
- "%(asctime)s | %(name)s | %(levelname)s | %(message)s",
64
- datefmt="%Y-%m-%d %H:%M:%S"
65
- )
66
- handler.setFormatter(file_formatter)
67
- logger.addHandler(handler)
68
-
69
- # 添加自定义 handler
70
- if custom_handlers:
71
- h = custom_handlers
72
- if h not in logger.handlers:
73
- file_formatter = logging.Formatter(
74
- "%(asctime)s | %(name)s | %(levelname)s | %(message)s",
75
- datefmt="%Y-%m-%d %H:%M:%S"
76
- )
77
- h.setFormatter(file_formatter)
78
- logger.addHandler(h)
79
- logger.addHandler(h)
80
-
81
- cls._logger_cache[cache_key] = logger
82
-
83
- return cls._logger_cache[cache_key]
84
-
85
-
86
- # 全局可用的 get_logger 函数(无需引用 LogManager)
87
- def get_logger(
88
- name: str=None,
89
- logger_cls: Type[logging.Logger] = logging.Logger,
90
- log_file: Optional[str] = None,
91
- add_console: bool = True,
92
- level: int = logging.INFO,
93
- custom_handlers: Optional[List[logging.Handler]] = None,
94
- ):
95
- """
96
- 便捷函数:获取日志记录器,无需关心 LogManager 实例化。
97
-
98
- 使用示例:
99
- from log_manager import get_logger
100
- logger = get_logger("my_module", log_file="app.log")
101
- logger.info("Hello world")
102
- """
103
- if name is None:
104
- name = "tmp_log"
105
-
106
- return LogManager.get_logger(
107
- name=name,
108
- logger_cls=logger_cls,
109
- log_file=log_file,
110
- add_console=add_console,
111
- level=level,
112
- custom_handlers=custom_handlers
113
- )
114
-
115
- # logger = LogManager().get_logger("tmp_log")
116
-
@@ -1,14 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: mlog_util
3
- Version: 0.1.3
4
- Summary: 自用日志库
5
- Classifier: Programming Language :: Python :: 3
6
- Classifier: License :: OSI Approved :: MIT License
7
- Classifier: Operating System :: OS Independent
8
- Requires-Python: >=3.6
9
- Requires-Dist: rich
10
- Requires-Dist: portalocker
11
- Dynamic: classifier
12
- Dynamic: requires-dist
13
- Dynamic: requires-python
14
- Dynamic: summary
@@ -1,9 +0,0 @@
1
- setup.py
2
- mlog_util/__init__.py
3
- mlog_util/handlers.py
4
- mlog_util/log_manager.py
5
- mlog_util.egg-info/PKG-INFO
6
- mlog_util.egg-info/SOURCES.txt
7
- mlog_util.egg-info/dependency_links.txt
8
- mlog_util.egg-info/requires.txt
9
- mlog_util.egg-info/top_level.txt
@@ -1,2 +0,0 @@
1
- rich
2
- portalocker
@@ -1 +0,0 @@
1
- mlog_util
mlog_util-0.1.3/setup.py DELETED
@@ -1,20 +0,0 @@
1
- from setuptools import setup, find_packages
2
-
3
- setup(
4
- name="mlog_util",
5
- version="0.1.3",
6
- packages=find_packages(),
7
- install_requires=["rich", "portalocker"], # 依赖库
8
- # author="may",
9
- # author_email="no",
10
- description="自用日志库",
11
- # long_description=open("README.md", encoding="utf-8").read(),
12
- # long_description_content_type="text/markdown",
13
-
14
- classifiers=[
15
- "Programming Language :: Python :: 3",
16
- "License :: OSI Approved :: MIT License",
17
- "Operating System :: OS Independent",
18
- ],
19
- python_requires='>=3.6',
20
- )
File without changes