agesuta 0.1.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.
agesuta-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 AgemameSutachi
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.
agesuta-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.1
2
+ Name: agesuta
3
+ Version: 0.1.0
4
+ Summary: A custom logging utility and other utilities with Rich console output, file handling, Slack notification, etc.
5
+ Home-page: https://github.com/AgemameSutachi/agesuta
6
+ Author: AgemameSutachi
7
+ Author-email: your.email@example.com
8
+ License: MIT
9
+ Keywords: logging custom logger rich file rotation slack requests utility
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
+ Classifier: Topic :: System :: Logging
14
+ Classifier: Topic :: Communications :: Chat
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.6
18
+ Classifier: Programming Language :: Python :: 3.7
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Requires-Python: >=3.6
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+
28
+ # agesuta
29
+
30
+ ## README.txtはAIによる生成ファイルです。(README.txt is a file generated by AI.)
31
+
32
+ Python標準の`logging`モジュールをベースにしたカスタムロギングユーティリティです。`rich`による色付きコンソール出力、カスタムローテーションハンドラによるファイルロギング、ログファイルのエンコーディング処理機能を備えています。
33
+
34
+ **注記:** 現在のバージョンに含まれるカスタムファイルローテーションハンドラ(`CustomLevelRotatingFileHandler`, `CustomDateRotatingFileHandler`)は、`CustomLogger.log_main`で生成されるファイル名との間に論理的な不整合がある可能性があります。これにより、一部の設定でログファイルが正しくローテーションされない場合があります。使用には注意が必要か、ハンドラの実装を確認してください。
35
+
36
+ ## インストール
37
+
38
+ ```bash
39
+ pip install agesuta
40
+ ```
41
+
42
+ ## 使用方法
43
+
44
+ **基本的な使用例を以下に示します:**
45
+
46
+ ```python
47
+ import logging
48
+ from agesuta import CustomLogger, log_decorator
49
+
50
+ # ロガーの初期設定を行うインスタンスを作成します
51
+ # これにより、ルートロガーにハンドラが設定されます
52
+ Cl_logger = CustomLogger(
53
+ flag_datelog=False, # 日付ベースの単一ログファイルにする場合は True に設定
54
+ dir_path="./Log",
55
+ log_encode="utf-8",
56
+ showlevel="INFO", # コンソール出力の最小レベル
57
+ maxBytes=5 * 1024 * 1024, # ログファイルを5MBでローテーション
58
+ backupCount=5 # バックアップファイルを最大5世代保持
59
+ )
60
+ Cl_logger.log_main() # ロギング設定を適用します
61
+
62
+ # 標準のlogging.getLogger()を使ってロガーインスタンスを取得します
63
+ # これは Cl_logger.log_main() で設定されたハンドラを使用します
64
+ logger = logging.getLogger(__name__)
65
+
66
+ logger.debug("これはデバッグメッセージです。")
67
+ logger.info("これは情報メッセージです。")
68
+ logger.warning("これは警告メッセージです。")
69
+ logger.error("これはエラーメッセージです。")
70
+ logger.critical("これはクリティカルメッセージです。")
71
+
72
+ # log_decorator の使用例
73
+ # from agesuta import log_decorator # パッケージ名に合わせて変更してください
74
+
75
+ # @log_decorator(logger)
76
+ # def my_function(arg1, arg2):
77
+ # logger.info("関数の中で何か処理しています")
78
+ # return arg1 + arg2
79
+
80
+ # result = my_function(10, 20)
81
+ # print(f"関数の結果: {result}")
82
+ ```
83
+
84
+ `flag_datelog` が `False` の場合、異なるレベル(例: `my_script_0_debug.log`, `my_script_1_info.log` など)ごとに個別のログファイルが `dir_path` に作成されます。
85
+ `flag_datelog` が `True` の場合、日付を含む単一のログファイル(例: `my_script_YYYY-MM-DD.log`)が作成されます。
86
+
87
+ ## CustomLogger パラメータ
88
+
89
+ - `flag_datelog` (`bool`): `True`の場合、日付ベースのログファイル命名規則(`basename_YYYY-MM-DD.log`)を使用し、`CustomDateRotatingFileHandler`を使用します。`False`(デフォルト)の場合、レベルベースのログファイル命名規則(`basename_level.log`)を使用し、`CustomLevelRotatingFileHandler`を使用します。
90
+ - `dir_path` (`str`): ログファイルが保存されるディレクトリです(デフォルト: `./Log`)。
91
+ - `log_encode` (`str`): ログファイルのエンコーディングです(デフォルト: `"utf-8"`)。初期化時に、異なるエンコーディングの既存ログファイルは変換されます。
92
+ - `maxBytes` (`int`): ログファイルがローテーションされるまでの最大バイト数です(デフォルト: `10 * 1024 * 1024` バイト、つまり 10MB)。
93
+ - `backupCount` (`int`): ローテーション後に保持するバックアップログファイルの数です(デフォルト: `10`)。
94
+ - `showlevel` (`str`): コンソール(RichHandlerを使用)に表示するログの最小レベルです。 `"DEBUG"`, `"INFO"`(デフォルト), `"WARNING"`, `"ERROR"`, `"CRITICAL"`, `"NOTSET"` を受け付けます。大文字小文字は区別されません。
95
+ - `flag_unnecessary_loggers_to_error` (`bool`): `True`(デフォルト)の場合、一般的で詳細なサードパーティライブラリ(例: `werkzeug`, `urllib3`, `httpx` など)のロガーレベルを `ERROR` に設定し、コンソールのノイズを減らします。
96
+
97
+ ## カスタムファイルハンドラ
98
+
99
+ このパッケージには、`logging.handlers.RotatingFileHandler` をベースにしたカスタムハンドラが含まれています:
100
+
101
+ - `NoColorFormatter`: ANSIエスケープシーケンスを取り除くロギングフォーマッターです。`RichHandler`使用時のプレーンテキストログファイルに有用です。
102
+ - `CustomLevelRotatingFileHandler`: サイズベースのローテーションを意図したカスタムハンドラで、`flag_datelog` が `False` の場合に使用されます。
103
+ - `CustomDateRotatingFileHandler`: 日付を意識した命名規則を持つサイズベースのローテーションを意図したカスタムハンドラで、`flag_datelog` が `True` の場合に使用されます。
104
+ **ローテーションに関する注記:** 上記で述べたように、カスタムハンドラのローテーションロジックと `CustomLogger.log_main` で生成されるファイル名との間に問題がある可能性があります。
105
+
106
+ ## log_decorator
107
+
108
+ 関数への入退室およびエラーを自動的に`DEBUG`レベルと`ERROR`レベルでログに記録するためのシンプルなデコレーター(`log_decorator`)が提供されています。
109
+
110
+ ## ライセンス
111
+
112
+ このプロジェクトはMITライセンスの下で提供されます - 詳細については LICENSE ファイルを参照してください。
@@ -0,0 +1,85 @@
1
+ # agesuta
2
+
3
+ ## README.txtはAIによる生成ファイルです。(README.txt is a file generated by AI.)
4
+
5
+ Python標準の`logging`モジュールをベースにしたカスタムロギングユーティリティです。`rich`による色付きコンソール出力、カスタムローテーションハンドラによるファイルロギング、ログファイルのエンコーディング処理機能を備えています。
6
+
7
+ **注記:** 現在のバージョンに含まれるカスタムファイルローテーションハンドラ(`CustomLevelRotatingFileHandler`, `CustomDateRotatingFileHandler`)は、`CustomLogger.log_main`で生成されるファイル名との間に論理的な不整合がある可能性があります。これにより、一部の設定でログファイルが正しくローテーションされない場合があります。使用には注意が必要か、ハンドラの実装を確認してください。
8
+
9
+ ## インストール
10
+
11
+ ```bash
12
+ pip install agesuta
13
+ ```
14
+
15
+ ## 使用方法
16
+
17
+ **基本的な使用例を以下に示します:**
18
+
19
+ ```python
20
+ import logging
21
+ from agesuta import CustomLogger, log_decorator
22
+
23
+ # ロガーの初期設定を行うインスタンスを作成します
24
+ # これにより、ルートロガーにハンドラが設定されます
25
+ Cl_logger = CustomLogger(
26
+ flag_datelog=False, # 日付ベースの単一ログファイルにする場合は True に設定
27
+ dir_path="./Log",
28
+ log_encode="utf-8",
29
+ showlevel="INFO", # コンソール出力の最小レベル
30
+ maxBytes=5 * 1024 * 1024, # ログファイルを5MBでローテーション
31
+ backupCount=5 # バックアップファイルを最大5世代保持
32
+ )
33
+ Cl_logger.log_main() # ロギング設定を適用します
34
+
35
+ # 標準のlogging.getLogger()を使ってロガーインスタンスを取得します
36
+ # これは Cl_logger.log_main() で設定されたハンドラを使用します
37
+ logger = logging.getLogger(__name__)
38
+
39
+ logger.debug("これはデバッグメッセージです。")
40
+ logger.info("これは情報メッセージです。")
41
+ logger.warning("これは警告メッセージです。")
42
+ logger.error("これはエラーメッセージです。")
43
+ logger.critical("これはクリティカルメッセージです。")
44
+
45
+ # log_decorator の使用例
46
+ # from agesuta import log_decorator # パッケージ名に合わせて変更してください
47
+
48
+ # @log_decorator(logger)
49
+ # def my_function(arg1, arg2):
50
+ # logger.info("関数の中で何か処理しています")
51
+ # return arg1 + arg2
52
+
53
+ # result = my_function(10, 20)
54
+ # print(f"関数の結果: {result}")
55
+ ```
56
+
57
+ `flag_datelog` が `False` の場合、異なるレベル(例: `my_script_0_debug.log`, `my_script_1_info.log` など)ごとに個別のログファイルが `dir_path` に作成されます。
58
+ `flag_datelog` が `True` の場合、日付を含む単一のログファイル(例: `my_script_YYYY-MM-DD.log`)が作成されます。
59
+
60
+ ## CustomLogger パラメータ
61
+
62
+ - `flag_datelog` (`bool`): `True`の場合、日付ベースのログファイル命名規則(`basename_YYYY-MM-DD.log`)を使用し、`CustomDateRotatingFileHandler`を使用します。`False`(デフォルト)の場合、レベルベースのログファイル命名規則(`basename_level.log`)を使用し、`CustomLevelRotatingFileHandler`を使用します。
63
+ - `dir_path` (`str`): ログファイルが保存されるディレクトリです(デフォルト: `./Log`)。
64
+ - `log_encode` (`str`): ログファイルのエンコーディングです(デフォルト: `"utf-8"`)。初期化時に、異なるエンコーディングの既存ログファイルは変換されます。
65
+ - `maxBytes` (`int`): ログファイルがローテーションされるまでの最大バイト数です(デフォルト: `10 * 1024 * 1024` バイト、つまり 10MB)。
66
+ - `backupCount` (`int`): ローテーション後に保持するバックアップログファイルの数です(デフォルト: `10`)。
67
+ - `showlevel` (`str`): コンソール(RichHandlerを使用)に表示するログの最小レベルです。 `"DEBUG"`, `"INFO"`(デフォルト), `"WARNING"`, `"ERROR"`, `"CRITICAL"`, `"NOTSET"` を受け付けます。大文字小文字は区別されません。
68
+ - `flag_unnecessary_loggers_to_error` (`bool`): `True`(デフォルト)の場合、一般的で詳細なサードパーティライブラリ(例: `werkzeug`, `urllib3`, `httpx` など)のロガーレベルを `ERROR` に設定し、コンソールのノイズを減らします。
69
+
70
+ ## カスタムファイルハンドラ
71
+
72
+ このパッケージには、`logging.handlers.RotatingFileHandler` をベースにしたカスタムハンドラが含まれています:
73
+
74
+ - `NoColorFormatter`: ANSIエスケープシーケンスを取り除くロギングフォーマッターです。`RichHandler`使用時のプレーンテキストログファイルに有用です。
75
+ - `CustomLevelRotatingFileHandler`: サイズベースのローテーションを意図したカスタムハンドラで、`flag_datelog` が `False` の場合に使用されます。
76
+ - `CustomDateRotatingFileHandler`: 日付を意識した命名規則を持つサイズベースのローテーションを意図したカスタムハンドラで、`flag_datelog` が `True` の場合に使用されます。
77
+ **ローテーションに関する注記:** 上記で述べたように、カスタムハンドラのローテーションロジックと `CustomLogger.log_main` で生成されるファイル名との間に問題がある可能性があります。
78
+
79
+ ## log_decorator
80
+
81
+ 関数への入退室およびエラーを自動的に`DEBUG`レベルと`ERROR`レベルでログに記録するためのシンプルなデコレーター(`log_decorator`)が提供されています。
82
+
83
+ ## ライセンス
84
+
85
+ このプロジェクトはMITライセンスの下で提供されます - 詳細については LICENSE ファイルを参照してください。
@@ -0,0 +1,5 @@
1
+ from .com import log_decorator,CustomLogger
2
+ from .configmanager import ConfigManager
3
+ from .slackapi import textpost,imagepost,imagepost_from_url
4
+
5
+ __version__ = '0.1.0'
@@ -0,0 +1,344 @@
1
+ import os
2
+ import logging
3
+ from datetime import datetime
4
+ from logging import Formatter
5
+ from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL, NOTSET
6
+ from rich.logging import RichHandler
7
+ from logging.handlers import RotatingFileHandler
8
+ from chardet.universaldetector import UniversalDetector
9
+ import inspect
10
+ import re
11
+ import sys
12
+
13
+
14
+ # ANSI エスケープシーケンスを除去する Formatter
15
+ class NoColorFormatter(logging.Formatter):
16
+ # ANSI エスケープシーケンスにマッチする正規表現
17
+ ANSI_ESCAPE = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")
18
+
19
+ def format(self, record):
20
+ msg = super().format(record)
21
+ # ANSI シーケンスを空文字に置換
22
+ return self.ANSI_ESCAPE.sub("", msg)
23
+
24
+
25
+ class CustomLevelRotatingFileHandler(RotatingFileHandler):
26
+ def doRollover(self):
27
+ """
28
+ ファイル名を basename.<番号>.<timestamp>.log にしてローテート。
29
+ ローテートのたびに既存ファイルの番号を+1し、最新を .1.<timestamp>.log にする。
30
+ """
31
+ if self.stream:
32
+ self.stream.close()
33
+ self.stream = None
34
+
35
+ base, ext = os.path.splitext(self.baseFilename)
36
+ timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
37
+
38
+ log_dir = os.path.dirname(self.baseFilename)
39
+ base_name = os.path.basename(base)
40
+
41
+ pattern = re.compile(
42
+ rf"^{re.escape(base_name)}\.(\d+)\.\d{{4}}-\d{{2}}-\d{{2}}_\d{{2}}-\d{{2}}-\d{{2}}{re.escape(ext)}$"
43
+ )
44
+ files_with_index = []
45
+
46
+ for fname in os.listdir(log_dir):
47
+ match = pattern.match(fname)
48
+ if match:
49
+ idx = int(match.group(1))
50
+ files_with_index.append((idx, fname))
51
+
52
+ # 番号が大きい順にずらす
53
+ for idx, fname in sorted(files_with_index, reverse=True):
54
+ full_path = os.path.join(log_dir, fname)
55
+ if idx >= self.backupCount:
56
+ os.remove(full_path)
57
+ else:
58
+ new_name = f"{base_name}.{idx + 1}.{fname.split('.', 2)[2]}"
59
+ os.rename(os.path.join(log_dir, fname), os.path.join(log_dir, new_name))
60
+
61
+ # 現在のログファイルを .1.<timestamp>.log にローテート
62
+ dfn = os.path.join(log_dir, f"{base_name}.1.{timestamp}{ext}")
63
+ if os.path.exists(dfn):
64
+ os.remove(dfn)
65
+ self.rotate(self.baseFilename, dfn)
66
+
67
+ if not self.delay:
68
+ self.stream = self._open()
69
+
70
+
71
+ class CustomDateRotatingFileHandler(RotatingFileHandler):
72
+ def doRollover(self):
73
+ """
74
+ ファイル名を basename_<timestamp>.<番号>.log にしてローテート。
75
+ ローテートのたびに既存ファイルの番号を+1し、最新を .1.<timestamp>.log にする。
76
+ """
77
+ if self.stream:
78
+ self.stream.close()
79
+ self.stream = None
80
+
81
+ base, ext = os.path.splitext(self.baseFilename)
82
+ log_dir = os.path.dirname(self.baseFilename)
83
+ base_name = os.path.basename(base)
84
+
85
+ # debug.N.log にマッチするファイルを探す
86
+ pattern = re.compile(rf"^{re.escape(base_name)}\.(\d+){re.escape(ext)}$")
87
+ files_with_index = []
88
+
89
+ for fname in os.listdir(log_dir):
90
+ match = pattern.match(fname)
91
+ if match:
92
+ idx = int(match.group(1))
93
+ files_with_index.append((idx, fname))
94
+
95
+ # 番号が大きい順にずらす
96
+ for idx, fname in sorted(files_with_index, reverse=True):
97
+ full_path = os.path.join(log_dir, fname)
98
+ if idx >= self.backupCount:
99
+ os.remove(full_path)
100
+ else:
101
+ new_name = f"{base_name}.{idx + 1}{ext}"
102
+ os.rename(os.path.join(log_dir, fname), os.path.join(log_dir, new_name))
103
+
104
+ # 現在のログファイルを .1.log にローテート
105
+ dfn = os.path.join(log_dir, f"{base_name}.1{ext}")
106
+ if os.path.exists(dfn):
107
+ os.remove(dfn)
108
+ self.rotate(self.baseFilename, dfn)
109
+
110
+ if not self.delay:
111
+ self.stream = self._open()
112
+
113
+
114
+ class CustomLogger:
115
+ def __init__(
116
+ self,
117
+ flag_datelog: bool = False,
118
+ dir_path: str = "./Log",
119
+ log_encode: str = "utf-8",
120
+ maxBytes: int = 10 * 1024 * 1024,
121
+ backupCount: int = 10,
122
+ showlevel="INFO",
123
+ flag_unnecessary_loggers_to_error=True,
124
+ ):
125
+ self.flag_datelog = bool(flag_datelog)
126
+ self.dir_path = str(dir_path)
127
+ self.log_encode = str(log_encode)
128
+ self.maxBytes = int(maxBytes)
129
+ self.backupCount = int(backupCount)
130
+ level_dic = {
131
+ "DEBUG": DEBUG,
132
+ "INFO": INFO,
133
+ "WARNING": WARNING,
134
+ "ERROR": ERROR,
135
+ "CRITICAL": CRITICAL,
136
+ "NOTSET": NOTSET,
137
+ }
138
+ self.showlevel = level_dic.get(showlevel.upper(), INFO)
139
+ if flag_unnecessary_loggers_to_error:
140
+ logger_names = [
141
+ "werkzeug",
142
+ "httpcore.http11",
143
+ "urllib3.connectionpool",
144
+ "googleapiclient.discovery_cache",
145
+ "googleapiclient.discovery",
146
+ "selenium.webdriver.remote.remote_connection",
147
+ "WDM",
148
+ "oauthlib.oauth1.rfc5849",
149
+ "requests_oauthlib.oauth1_auth",
150
+ "httpx"
151
+ ]
152
+ for name in logger_names:
153
+ logging.getLogger(name).setLevel(logging.ERROR)
154
+
155
+ def encode_detect(self, filepath):
156
+ if not os.path.exists(filepath):
157
+ return 1, ""
158
+ try:
159
+ try:
160
+ detector = UniversalDetector()
161
+ with open(filepath, "rb") as f:
162
+ while True:
163
+ binary = f.readline()
164
+ if binary == b"":
165
+ break
166
+ detector.feed(binary)
167
+ if detector.done:
168
+ break
169
+ finally:
170
+ detector.close()
171
+ # print("encoding:" + str(detector.result["encoding"]))
172
+ if detector.result["encoding"] is None:
173
+ return 0, "CP932"
174
+ elif detector.result["encoding"] in ["utf-8", "UTF-8-SIG"]:
175
+ return 0, "utf-8"
176
+ elif detector.result["encoding"] in ["CP932", "SHIFT_JIS", "Windows-1254"]:
177
+ return 0, "CP932"
178
+ else:
179
+ return 0, detector.result["encoding"]
180
+ except:
181
+ return 2, ""
182
+
183
+ def change_encode(self, filepath, after_encode):
184
+ try:
185
+ ret, before_encode = self.encode_detect(filepath)
186
+ if ret == 1:
187
+ # ファイルがない場合はそのまま返す
188
+ return 1
189
+ if before_encode == after_encode:
190
+ # 再エンコードが不要な場合はそのまま返す
191
+ return 0
192
+ try:
193
+ os.rename(filepath, filepath + "_bk")
194
+ except:
195
+ if os.path.exists(filepath):
196
+ os.remove(filepath)
197
+ # リネーム失敗時は削除して返す
198
+ return 1
199
+ if ret == 2:
200
+ # エンコードの読み取り失敗時はリネームして返す
201
+ return 1
202
+ try:
203
+ with open(filepath + "_bk", "r", encoding=before_encode) as f:
204
+ txt = f.read()
205
+ with open(filepath, "w", encoding=after_encode) as f:
206
+ f.write(txt)
207
+ os.remove(filepath + "_bk")
208
+ except:
209
+ if os.path.exists(filepath):
210
+ os.remove(filepath)
211
+ return 1
212
+ return 0
213
+ except:
214
+ return 1
215
+
216
+ def get_script_display_name(self):
217
+ # PyInstallerなどでexe化している場合
218
+ if getattr(sys, "frozen", False):
219
+ # sys.executable はexeのパスなので、
220
+ # ここでbasename (拡張子なし) を取得
221
+ base = os.path.basename(sys.executable)
222
+ name, _ = os.path.splitext(base)
223
+ return name + "_"
224
+ else:
225
+ # 通常のスクリプト実行の場合
226
+ # __main__モジュールの__file__が使えるのでそれを利用
227
+ try:
228
+ # __main__モジュールがあれば
229
+ import __main__
230
+
231
+ if hasattr(__main__, "__file__"):
232
+ base = os.path.basename(__main__.__file__)
233
+ name, _ = os.path.splitext(base)
234
+ return name + "_"
235
+ except Exception:
236
+ pass
237
+
238
+ # もし上記で取得できなかった場合は、inspectでスタックから探す
239
+ for frame in inspect.stack():
240
+ module = inspect.getmodule(frame[0])
241
+ if module and hasattr(module, "__file__"):
242
+ base = os.path.basename(module.__file__)
243
+ name, _ = os.path.splitext(base)
244
+ return name + "_"
245
+ # もし何も見つからなければ空文字
246
+ return ""
247
+
248
+ def log_main(self):
249
+ handlers = []
250
+ importname = self.get_script_display_name()
251
+
252
+ # ストリームハンドラの設定
253
+ rich_handler: RichHandler = RichHandler(rich_tracebacks=True)
254
+ rich_handler.setLevel(self.showlevel)
255
+ rich_handler.setFormatter(NoColorFormatter("%(message)s"))
256
+ handlers.append(rich_handler)
257
+
258
+ # 保存先の有無チェック
259
+ if not os.path.isdir(self.dir_path):
260
+ os.makedirs(self.dir_path, exist_ok=True)
261
+
262
+ # ファイルハンドラの設定
263
+ if self.flag_datelog:
264
+ logfile_path = f"{self.dir_path}/{importname}{datetime.now():%Y-%m-%d}.log"
265
+ if os.path.exists(logfile_path):
266
+ ret = self.change_encode(logfile_path, self.log_encode)
267
+ file_handler = CustomDateRotatingFileHandler(
268
+ logfile_path,
269
+ "a",
270
+ maxBytes=self.maxBytes,
271
+ backupCount=self.backupCount,
272
+ encoding=self.log_encode,
273
+ )
274
+ file_handler.setLevel(DEBUG)
275
+ file_handler.setFormatter(
276
+ # Formatter("%(asctime)s [%(levelname).4s] %(filename)s %(funcName)s %(lineno)d: %(message)s")
277
+ NoColorFormatter(
278
+ "%(asctime)s [%(levelname)s] %(name)s %(filename)s %(funcName)s %(lineno)d: %(message)s"
279
+ )
280
+ )
281
+ handlers.append(file_handler)
282
+
283
+ # ルートロガーの設定
284
+ logging.basicConfig(level=NOTSET, handlers=handlers)
285
+ else:
286
+ loggger_dic = {
287
+ f"{importname}0_debug": DEBUG,
288
+ f"{importname}1_info": INFO,
289
+ f"{importname}2_warning": WARNING,
290
+ f"{importname}3_error": ERROR,
291
+ }
292
+ for i in list(loggger_dic.keys()):
293
+ logfile_path = f"{self.dir_path}/{i}.log"
294
+ if os.path.exists(logfile_path):
295
+ ret = self.change_encode(logfile_path, self.log_encode)
296
+ logger_temp = CustomLevelRotatingFileHandler(
297
+ logfile_path,
298
+ "a",
299
+ maxBytes=self.maxBytes,
300
+ backupCount=self.backupCount,
301
+ encoding=self.log_encode,
302
+ )
303
+ logger_temp.setLevel(loggger_dic[i])
304
+ logger_temp.setFormatter(
305
+ # Formatter("%(asctime)s [%(levelname).4s] %(filename)s %(funcName)s %(lineno)d: %(message)s")
306
+ NoColorFormatter(
307
+ "%(asctime)s [%(levelname)s] %(name)s %(filename)s %(funcName)s %(lineno)d: %(message)s"
308
+ )
309
+ )
310
+ handlers.append(logger_temp)
311
+
312
+ # ルートロガーの設定
313
+ logging.basicConfig(level=NOTSET, handlers=handlers)
314
+
315
+
316
+ def log_decorator(logger):
317
+ def _log_decorator(func):
318
+ def wrapper(*args, **kwargs):
319
+ local_args = locals()
320
+ try:
321
+ logger.debug(f"start: {func.__name__} args: {str(local_args)}")
322
+ return_val = func(*args, **kwargs)
323
+ logger.debug(f" end: {func.__name__} ret: {str(return_val)}")
324
+ # logger.debug(f" end: {func.__name__}")
325
+ return return_val
326
+ except Exception as e:
327
+ logger.error(f"error: {func.__name__}")
328
+ raise e
329
+
330
+ return wrapper
331
+
332
+ return _log_decorator
333
+
334
+
335
+ if __name__ == "__main__":
336
+ Cl_logger = CustomLogger(flag_datelog=False, dir_path="./Log", log_encode="utf-8")
337
+ Cl_logger.log_main()
338
+ logger = logging.getLogger(__name__)
339
+ logger.debug("テスト: debug")
340
+ logger.info("テスト: info")
341
+ logger.warning("テスト: warning")
342
+ logger.error("テスト: error")
343
+ logger.critical("テスト: critical")
344
+ os.system("PAUSE")