DefStream 0.1.7__tar.gz → 0.1.9__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.
- {defstream-0.1.7 → defstream-0.1.9}/DefStream.egg-info/PKG-INFO +52 -1
- {defstream-0.1.7 → defstream-0.1.9}/DefStream.egg-info/SOURCES.txt +10 -0
- {defstream-0.1.7 → defstream-0.1.9}/PKG-INFO +52 -1
- {defstream-0.1.7 → defstream-0.1.9}/README.en.md +7 -0
- {defstream-0.1.7 → defstream-0.1.9}/README.md +51 -0
- defstream-0.1.9/issues/feature/8/IMPLEMENTS.md +106 -0
- defstream-0.1.9/issues/feature/8/README.md +40 -0
- defstream-0.1.9/issues/feature/8/REQUIREMENTS.md +168 -0
- defstream-0.1.9/issues/feature/8/ci.refs.json +4 -0
- defstream-0.1.9/issues/fix/6/IMPLEMENTS.md +134 -0
- defstream-0.1.9/issues/fix/6/README.md +58 -0
- defstream-0.1.9/issues/fix/6/REQUIREMENTS.md +241 -0
- {defstream-0.1.7 → defstream-0.1.9}/sample/Broker/Sample.py +46 -8
- {defstream-0.1.7 → defstream-0.1.9}/sample/Worker/RabbitMQ/Client.py +14 -6
- {defstream-0.1.7 → defstream-0.1.9}/sample/Worker/RabbitMQ/Tasks.py +41 -2
- {defstream-0.1.7 → defstream-0.1.9}/sample/Worker/RabbitMQ/Worker.py +9 -3
- {defstream-0.1.7 → defstream-0.1.9}/sample/Worker/Redis/Sample.py +39 -4
- {defstream-0.1.7 → defstream-0.1.9}/sample/Worker/Sample.py +33 -7
- {defstream-0.1.7 → defstream-0.1.9}/src/Descriptor/DataObject.py +74 -49
- {defstream-0.1.7 → defstream-0.1.9}/src/Descriptor/Types.py +49 -30
- {defstream-0.1.7 → defstream-0.1.9}/src/Descriptor/Value.py +86 -30
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Extensions/Console.py +40 -11
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Extensions/Dashboard.py +10 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Extensions/HealthCheck.py +21 -6
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Extensions/Metrics.py +34 -1
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Extensions/Specifications.py +22 -7
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Inspector.py +148 -17
- {defstream-0.1.7 → defstream-0.1.9}/src/Worker/Executor.py +74 -1
- {defstream-0.1.7 → defstream-0.1.9}/src/Worker/Pool.py +42 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Worker/Run.py +73 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Worker/Worker.py +118 -17
- defstream-0.1.9/test/test_descriptor.py +547 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_inspector.py +2 -2
- defstream-0.1.9/test/test_inspector_logging.py +148 -0
- defstream-0.1.9/test/test_logging.py +329 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_runner_hooks.py +1 -1
- {defstream-0.1.7 → defstream-0.1.9}/test/test_specifications.py +1 -1
- {defstream-0.1.7 → defstream-0.1.9}/test/test_task_messages.py +1 -1
- {defstream-0.1.7 → defstream-0.1.9}/test/test_worker.py +2 -2
- {defstream-0.1.7 → defstream-0.1.9}/.github/workflows/ci.yml +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/.gitignore +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/DefStream.egg-info/dependency_links.txt +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/DefStream.egg-info/requires.txt +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/DefStream.egg-info/top_level.txt +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/LICENSE +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/issues/feature/1/IMPLEMENTS.md +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/issues/feature/1/README.md +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/issues/feature/1/REQUIREMENTS.md +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/issues/feature/1/TASK.md +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/issues/feature/1/ci.refs.json +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/issues/fix/3/IMPLEMENTS.md +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/issues/fix/3/README.md +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/issues/fix/3/REQUIREMENTS.md +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/issues/fix/3/ci.refs.json +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/setup.cfg +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/setup.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/Configuration.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/Connection.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/Consumer.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/Errors.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/Event.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/Implements/__init__.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/Policies.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/Priority.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/Protocol.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Broker/__init__.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Descriptor/__init__.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Extension.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Extensions/Console.html +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Extensions/Dashboard.html +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Extensions/__init__.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/Response.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Inspector/__init__.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Pattern.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/Array.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/Common.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/Compare.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/Condition.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/DataObject.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/DateTime.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/Number.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/Object.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/Size.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/String.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/Type.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Patterns/__init__.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Validate.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/Validator.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Validator/__init__.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Worker/Message.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Worker/Specification.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Worker/Startup.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/Worker/__init__.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/src/__init__.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_dashboard.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_dashboard_ui.cjs +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_inspector_console.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_lifecycle_hooks.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_pool_callbacks.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_process_signals.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_protocol_contracts.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_release_workflow.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_task_priorities.py +0 -0
- {defstream-0.1.7 → defstream-0.1.9}/test/test_worker_startup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DefStream
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: Synchronous message processing with pluggable broker adapters
|
|
5
5
|
Home-page: https://github.com/yong5eon/DefStream
|
|
6
6
|
Author: Heo Yongseon
|
|
@@ -59,9 +59,60 @@ DefStream은 메시지 브로커에서 받은 작업을 일반 Python 함수처
|
|
|
59
59
|
- [생명주기 훅](#생명주기-훅)
|
|
60
60
|
- [요청·응답 계약과 검증](#요청응답-계약과-검증)
|
|
61
61
|
- [상태 확인과 작업 콘솔](#상태-확인과-작업-콘솔)
|
|
62
|
+
- [로깅](#로깅)
|
|
62
63
|
- [브로커 선택과 운영 주의사항](#브로커-선택과-운영-주의사항)
|
|
63
64
|
- [예제와 라이선스](#예제와-라이선스)
|
|
64
65
|
|
|
66
|
+
## 로깅
|
|
67
|
+
|
|
68
|
+
DefStream은 표준 `logging`으로 기록하며 핸들러·포매터·레벨을 설정하지 않습니다.
|
|
69
|
+
애플리케이션에서 필요한 출처만 선택해 출력하세요. 샘플은 `Sample`과 `DefStream`
|
|
70
|
+
이름 및 그 하위 로거만 출력하며, 샘플의 `print()`는 로그로 대체했습니다.
|
|
71
|
+
Worker의 기존 시작 배너는 로깅 설정과 무관하게 그대로 출력됩니다.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from logging import DEBUG, Filter, Formatter, StreamHandler, getLogger
|
|
75
|
+
|
|
76
|
+
sources = (Filter('Sample'), Filter('DefStream'))
|
|
77
|
+
handler = StreamHandler()
|
|
78
|
+
handler.setFormatter(Formatter(
|
|
79
|
+
'%(asctime)s %(processName)s %(name)s %(levelname)s %(message)s'
|
|
80
|
+
))
|
|
81
|
+
handler.addFilter(lambda record: any(source.filter(record) for source in sources))
|
|
82
|
+
root = getLogger()
|
|
83
|
+
root.setLevel(DEBUG)
|
|
84
|
+
root.addHandler(handler)
|
|
85
|
+
|
|
86
|
+
logger = getLogger('Sample')
|
|
87
|
+
logger.info('Application started')
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
필터는 루트 로거가 아닌 **핸들러**에 적용합니다. `Filter('DefStream')`은
|
|
91
|
+
`DefStream`과 `DefStream.` 하위 이름을 포함하지만 `DefStreamExtra`는 포함하지 않습니다.
|
|
92
|
+
위 설정은 독립 실행 애플리케이션을 위한 예제이며, 이미 있는 다른 핸들러의 출력은 바꾸지 않습니다.
|
|
93
|
+
브로커만 보고 싶으면 `DefStream` 대신 `DefStream.Broker.Implements.RabbitMQ` 또는
|
|
94
|
+
`DefStream.Broker.Implements.Redis`를 선택할 수 있습니다.
|
|
95
|
+
|
|
96
|
+
- 클래스 멤버 `logger`에 `DefStream.Worker`, `DefStream.Run`, `DefStream.Executor`,
|
|
97
|
+
`DefStream.Pool`, `DefStream.ThreadPool`, `DefStream.ProcessPool`을 사용합니다.
|
|
98
|
+
- Pool 공통 메서드도 실제 풀의 로거 멤버를 사용합니다. 사용자 하위 클래스는 기본 이름을
|
|
99
|
+
상속하며 원하면 `logger`를 명시적으로 재정의할 수 있습니다.
|
|
100
|
+
- Inspector·Server·RequestHandler는 `DefStream.Inspector`를 공유합니다.
|
|
101
|
+
HTTP 요청 수신은 DEBUG, 응답 상태와 전송 결과는 INFO입니다.
|
|
102
|
+
확장 고유 로그는 `DefStream.Inspector.Extensions.<확장 이름>`을 사용합니다.
|
|
103
|
+
- 정상 메시지별 처리 흐름은 DEBUG, 생명주기는 INFO, 주의할 사건은 WARNING,
|
|
104
|
+
처리 실패는 ERROR로 기록합니다. 본문·결과·인증정보는 기본 로그에 포함하지 않습니다.
|
|
105
|
+
- 핸들러가 전혀 없으면 Python의 `lastResort`에 의해 WARNING 이상이 stderr에 나올 수 있습니다.
|
|
106
|
+
사용자 예외 메시지에는 민감한 값을 넣지 마세요. 실패 traceback에 예외 메시지가 포함됩니다.
|
|
107
|
+
|
|
108
|
+
ProcessPool은 `spawn` 자식 프로세스를 사용하므로 부모의 핸들러가 자동으로 전달되지 않습니다.
|
|
109
|
+
자식도 로그를 출력하려면 import 가능한 `PoolSetup` 구현에서 같은 설정을 적용하고
|
|
110
|
+
`ProcessPool(..., setups=...)`로 전달하세요. 자식 초기화 훅이 실행되기 전의 DEBUG·INFO는
|
|
111
|
+
그 설정으로 수신할 수 없습니다.
|
|
112
|
+
[RabbitMQ 작업 예제의 LoggingSetup](./sample/Worker/RabbitMQ/Tasks.py)과
|
|
113
|
+
[부모·자식 설정 예제](./sample/Worker/RabbitMQ/Worker.py)를 참고하세요.
|
|
114
|
+
기존 애플리케이션에서는 이미 설정한 핸들러를 반복 추가하지 않도록 초기화 위치를 관리해야 합니다.
|
|
115
|
+
|
|
65
116
|
## 설치
|
|
66
117
|
|
|
67
118
|
Python **3.9 이상**이 필요합니다. 실제 메시지 처리를 위해 사용할 브로커 서버도 준비하세요.
|
|
@@ -14,10 +14,17 @@ issues/feature/1/README.md
|
|
|
14
14
|
issues/feature/1/REQUIREMENTS.md
|
|
15
15
|
issues/feature/1/TASK.md
|
|
16
16
|
issues/feature/1/ci.refs.json
|
|
17
|
+
issues/feature/8/IMPLEMENTS.md
|
|
18
|
+
issues/feature/8/README.md
|
|
19
|
+
issues/feature/8/REQUIREMENTS.md
|
|
20
|
+
issues/feature/8/ci.refs.json
|
|
17
21
|
issues/fix/3/IMPLEMENTS.md
|
|
18
22
|
issues/fix/3/README.md
|
|
19
23
|
issues/fix/3/REQUIREMENTS.md
|
|
20
24
|
issues/fix/3/ci.refs.json
|
|
25
|
+
issues/fix/6/IMPLEMENTS.md
|
|
26
|
+
issues/fix/6/README.md
|
|
27
|
+
issues/fix/6/REQUIREMENTS.md
|
|
21
28
|
sample/Broker/Sample.py
|
|
22
29
|
sample/Worker/Sample.py
|
|
23
30
|
sample/Worker/RabbitMQ/Client.py
|
|
@@ -77,9 +84,12 @@ src/Worker/Worker.py
|
|
|
77
84
|
src/Worker/__init__.py
|
|
78
85
|
test/test_dashboard.py
|
|
79
86
|
test/test_dashboard_ui.cjs
|
|
87
|
+
test/test_descriptor.py
|
|
80
88
|
test/test_inspector.py
|
|
81
89
|
test/test_inspector_console.py
|
|
90
|
+
test/test_inspector_logging.py
|
|
82
91
|
test/test_lifecycle_hooks.py
|
|
92
|
+
test/test_logging.py
|
|
83
93
|
test/test_pool_callbacks.py
|
|
84
94
|
test/test_process_signals.py
|
|
85
95
|
test/test_protocol_contracts.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DefStream
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: Synchronous message processing with pluggable broker adapters
|
|
5
5
|
Home-page: https://github.com/yong5eon/DefStream
|
|
6
6
|
Author: Heo Yongseon
|
|
@@ -59,9 +59,60 @@ DefStream은 메시지 브로커에서 받은 작업을 일반 Python 함수처
|
|
|
59
59
|
- [생명주기 훅](#생명주기-훅)
|
|
60
60
|
- [요청·응답 계약과 검증](#요청응답-계약과-검증)
|
|
61
61
|
- [상태 확인과 작업 콘솔](#상태-확인과-작업-콘솔)
|
|
62
|
+
- [로깅](#로깅)
|
|
62
63
|
- [브로커 선택과 운영 주의사항](#브로커-선택과-운영-주의사항)
|
|
63
64
|
- [예제와 라이선스](#예제와-라이선스)
|
|
64
65
|
|
|
66
|
+
## 로깅
|
|
67
|
+
|
|
68
|
+
DefStream은 표준 `logging`으로 기록하며 핸들러·포매터·레벨을 설정하지 않습니다.
|
|
69
|
+
애플리케이션에서 필요한 출처만 선택해 출력하세요. 샘플은 `Sample`과 `DefStream`
|
|
70
|
+
이름 및 그 하위 로거만 출력하며, 샘플의 `print()`는 로그로 대체했습니다.
|
|
71
|
+
Worker의 기존 시작 배너는 로깅 설정과 무관하게 그대로 출력됩니다.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from logging import DEBUG, Filter, Formatter, StreamHandler, getLogger
|
|
75
|
+
|
|
76
|
+
sources = (Filter('Sample'), Filter('DefStream'))
|
|
77
|
+
handler = StreamHandler()
|
|
78
|
+
handler.setFormatter(Formatter(
|
|
79
|
+
'%(asctime)s %(processName)s %(name)s %(levelname)s %(message)s'
|
|
80
|
+
))
|
|
81
|
+
handler.addFilter(lambda record: any(source.filter(record) for source in sources))
|
|
82
|
+
root = getLogger()
|
|
83
|
+
root.setLevel(DEBUG)
|
|
84
|
+
root.addHandler(handler)
|
|
85
|
+
|
|
86
|
+
logger = getLogger('Sample')
|
|
87
|
+
logger.info('Application started')
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
필터는 루트 로거가 아닌 **핸들러**에 적용합니다. `Filter('DefStream')`은
|
|
91
|
+
`DefStream`과 `DefStream.` 하위 이름을 포함하지만 `DefStreamExtra`는 포함하지 않습니다.
|
|
92
|
+
위 설정은 독립 실행 애플리케이션을 위한 예제이며, 이미 있는 다른 핸들러의 출력은 바꾸지 않습니다.
|
|
93
|
+
브로커만 보고 싶으면 `DefStream` 대신 `DefStream.Broker.Implements.RabbitMQ` 또는
|
|
94
|
+
`DefStream.Broker.Implements.Redis`를 선택할 수 있습니다.
|
|
95
|
+
|
|
96
|
+
- 클래스 멤버 `logger`에 `DefStream.Worker`, `DefStream.Run`, `DefStream.Executor`,
|
|
97
|
+
`DefStream.Pool`, `DefStream.ThreadPool`, `DefStream.ProcessPool`을 사용합니다.
|
|
98
|
+
- Pool 공통 메서드도 실제 풀의 로거 멤버를 사용합니다. 사용자 하위 클래스는 기본 이름을
|
|
99
|
+
상속하며 원하면 `logger`를 명시적으로 재정의할 수 있습니다.
|
|
100
|
+
- Inspector·Server·RequestHandler는 `DefStream.Inspector`를 공유합니다.
|
|
101
|
+
HTTP 요청 수신은 DEBUG, 응답 상태와 전송 결과는 INFO입니다.
|
|
102
|
+
확장 고유 로그는 `DefStream.Inspector.Extensions.<확장 이름>`을 사용합니다.
|
|
103
|
+
- 정상 메시지별 처리 흐름은 DEBUG, 생명주기는 INFO, 주의할 사건은 WARNING,
|
|
104
|
+
처리 실패는 ERROR로 기록합니다. 본문·결과·인증정보는 기본 로그에 포함하지 않습니다.
|
|
105
|
+
- 핸들러가 전혀 없으면 Python의 `lastResort`에 의해 WARNING 이상이 stderr에 나올 수 있습니다.
|
|
106
|
+
사용자 예외 메시지에는 민감한 값을 넣지 마세요. 실패 traceback에 예외 메시지가 포함됩니다.
|
|
107
|
+
|
|
108
|
+
ProcessPool은 `spawn` 자식 프로세스를 사용하므로 부모의 핸들러가 자동으로 전달되지 않습니다.
|
|
109
|
+
자식도 로그를 출력하려면 import 가능한 `PoolSetup` 구현에서 같은 설정을 적용하고
|
|
110
|
+
`ProcessPool(..., setups=...)`로 전달하세요. 자식 초기화 훅이 실행되기 전의 DEBUG·INFO는
|
|
111
|
+
그 설정으로 수신할 수 없습니다.
|
|
112
|
+
[RabbitMQ 작업 예제의 LoggingSetup](./sample/Worker/RabbitMQ/Tasks.py)과
|
|
113
|
+
[부모·자식 설정 예제](./sample/Worker/RabbitMQ/Worker.py)를 참고하세요.
|
|
114
|
+
기존 애플리케이션에서는 이미 설정한 핸들러를 반복 추가하지 않도록 초기화 위치를 관리해야 합니다.
|
|
115
|
+
|
|
65
116
|
## 설치
|
|
66
117
|
|
|
67
118
|
Python **3.9 이상**이 필요합니다. 실제 메시지 처리를 위해 사용할 브로커 서버도 준비하세요.
|
|
@@ -30,6 +30,13 @@ Configure execution, acknowledgements, failure policies, and monitoring without
|
|
|
30
30
|
- [Broker selection and operational considerations](#broker-selection-and-operational-considerations)
|
|
31
31
|
- [Examples and license](#examples-and-license)
|
|
32
32
|
|
|
33
|
+
## 로깅 지원
|
|
34
|
+
|
|
35
|
+
클래스별 표준 로거와 사용자 주도 핸들러 설정을 지원합니다.
|
|
36
|
+
샘플은 `Sample` 및 `DefStream` 계층만 출력하며, ProcessPool 자식은 별도 setup 훅으로
|
|
37
|
+
출력을 설정합니다. Worker의 시작 배너는 유지됩니다.
|
|
38
|
+
로거 이름, 선택 수신, 예외 메시지 주의사항과 프로세스 설정은 [로깅 안내](./README.md#로깅)를 참고하세요.
|
|
39
|
+
|
|
33
40
|
## Installation
|
|
34
41
|
|
|
35
42
|
Requires Python **3.9 or newer**. Prepare the broker server you intend to use.
|
|
@@ -26,9 +26,60 @@ DefStream은 메시지 브로커에서 받은 작업을 일반 Python 함수처
|
|
|
26
26
|
- [생명주기 훅](#생명주기-훅)
|
|
27
27
|
- [요청·응답 계약과 검증](#요청응답-계약과-검증)
|
|
28
28
|
- [상태 확인과 작업 콘솔](#상태-확인과-작업-콘솔)
|
|
29
|
+
- [로깅](#로깅)
|
|
29
30
|
- [브로커 선택과 운영 주의사항](#브로커-선택과-운영-주의사항)
|
|
30
31
|
- [예제와 라이선스](#예제와-라이선스)
|
|
31
32
|
|
|
33
|
+
## 로깅
|
|
34
|
+
|
|
35
|
+
DefStream은 표준 `logging`으로 기록하며 핸들러·포매터·레벨을 설정하지 않습니다.
|
|
36
|
+
애플리케이션에서 필요한 출처만 선택해 출력하세요. 샘플은 `Sample`과 `DefStream`
|
|
37
|
+
이름 및 그 하위 로거만 출력하며, 샘플의 `print()`는 로그로 대체했습니다.
|
|
38
|
+
Worker의 기존 시작 배너는 로깅 설정과 무관하게 그대로 출력됩니다.
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from logging import DEBUG, Filter, Formatter, StreamHandler, getLogger
|
|
42
|
+
|
|
43
|
+
sources = (Filter('Sample'), Filter('DefStream'))
|
|
44
|
+
handler = StreamHandler()
|
|
45
|
+
handler.setFormatter(Formatter(
|
|
46
|
+
'%(asctime)s %(processName)s %(name)s %(levelname)s %(message)s'
|
|
47
|
+
))
|
|
48
|
+
handler.addFilter(lambda record: any(source.filter(record) for source in sources))
|
|
49
|
+
root = getLogger()
|
|
50
|
+
root.setLevel(DEBUG)
|
|
51
|
+
root.addHandler(handler)
|
|
52
|
+
|
|
53
|
+
logger = getLogger('Sample')
|
|
54
|
+
logger.info('Application started')
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
필터는 루트 로거가 아닌 **핸들러**에 적용합니다. `Filter('DefStream')`은
|
|
58
|
+
`DefStream`과 `DefStream.` 하위 이름을 포함하지만 `DefStreamExtra`는 포함하지 않습니다.
|
|
59
|
+
위 설정은 독립 실행 애플리케이션을 위한 예제이며, 이미 있는 다른 핸들러의 출력은 바꾸지 않습니다.
|
|
60
|
+
브로커만 보고 싶으면 `DefStream` 대신 `DefStream.Broker.Implements.RabbitMQ` 또는
|
|
61
|
+
`DefStream.Broker.Implements.Redis`를 선택할 수 있습니다.
|
|
62
|
+
|
|
63
|
+
- 클래스 멤버 `logger`에 `DefStream.Worker`, `DefStream.Run`, `DefStream.Executor`,
|
|
64
|
+
`DefStream.Pool`, `DefStream.ThreadPool`, `DefStream.ProcessPool`을 사용합니다.
|
|
65
|
+
- Pool 공통 메서드도 실제 풀의 로거 멤버를 사용합니다. 사용자 하위 클래스는 기본 이름을
|
|
66
|
+
상속하며 원하면 `logger`를 명시적으로 재정의할 수 있습니다.
|
|
67
|
+
- Inspector·Server·RequestHandler는 `DefStream.Inspector`를 공유합니다.
|
|
68
|
+
HTTP 요청 수신은 DEBUG, 응답 상태와 전송 결과는 INFO입니다.
|
|
69
|
+
확장 고유 로그는 `DefStream.Inspector.Extensions.<확장 이름>`을 사용합니다.
|
|
70
|
+
- 정상 메시지별 처리 흐름은 DEBUG, 생명주기는 INFO, 주의할 사건은 WARNING,
|
|
71
|
+
처리 실패는 ERROR로 기록합니다. 본문·결과·인증정보는 기본 로그에 포함하지 않습니다.
|
|
72
|
+
- 핸들러가 전혀 없으면 Python의 `lastResort`에 의해 WARNING 이상이 stderr에 나올 수 있습니다.
|
|
73
|
+
사용자 예외 메시지에는 민감한 값을 넣지 마세요. 실패 traceback에 예외 메시지가 포함됩니다.
|
|
74
|
+
|
|
75
|
+
ProcessPool은 `spawn` 자식 프로세스를 사용하므로 부모의 핸들러가 자동으로 전달되지 않습니다.
|
|
76
|
+
자식도 로그를 출력하려면 import 가능한 `PoolSetup` 구현에서 같은 설정을 적용하고
|
|
77
|
+
`ProcessPool(..., setups=...)`로 전달하세요. 자식 초기화 훅이 실행되기 전의 DEBUG·INFO는
|
|
78
|
+
그 설정으로 수신할 수 없습니다.
|
|
79
|
+
[RabbitMQ 작업 예제의 LoggingSetup](./sample/Worker/RabbitMQ/Tasks.py)과
|
|
80
|
+
[부모·자식 설정 예제](./sample/Worker/RabbitMQ/Worker.py)를 참고하세요.
|
|
81
|
+
기존 애플리케이션에서는 이미 설정한 핸들러를 반복 추가하지 않도록 초기화 위치를 관리해야 합니다.
|
|
82
|
+
|
|
32
83
|
## 설치
|
|
33
84
|
|
|
34
85
|
Python **3.9 이상**이 필요합니다. 실제 메시지 처리를 위해 사용할 브로커 서버도 준비하세요.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# 로깅 지원 구현 기록
|
|
2
|
+
|
|
3
|
+
## 1. 구현 개요
|
|
4
|
+
|
|
5
|
+
[요구사항](./REQUIREMENTS.md)에 따라 Worker 실행 흐름과 Inspector에 Python 표준
|
|
6
|
+
`logging`을 적용했다. 출력 정책은 애플리케이션에 맡기고 클래스별 명시적 로거로
|
|
7
|
+
관찰 지점을 제공한다.
|
|
8
|
+
|
|
9
|
+
- 구현·검증일: 2026-10-20
|
|
10
|
+
- 사용자용 안내: [변경 로그](./README.md)
|
|
11
|
+
- 연계 구현: [RabbitMQ](../../../../DefStream-RabbitMQ/issues/feature/5/IMPLEMENTS.md),
|
|
12
|
+
[Redis](../../../../DefStream-Redis/issues/feature/5/IMPLEMENTS.md)
|
|
13
|
+
|
|
14
|
+
## 2. 클래스별 로거와 기록 책임
|
|
15
|
+
|
|
16
|
+
로거는 클래스 멤버 `logger`로 정의하고 공통 메서드는 `self.logger`를 사용한다.
|
|
17
|
+
사용자 하위 클래스의 이름을 자동으로 사용하지 않으며, 명시적으로 재정의할 수 있다.
|
|
18
|
+
|
|
19
|
+
| 대상 | 로거 이름 | 구현한 관찰 지점 |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| [Worker](../../../src/Worker/Worker.py) | `DefStream.Worker` | 작업 등록, 연결·구독·훅, 수신·제출, 성공·실패 정책, 종료·미확인 메시지 |
|
|
22
|
+
| [Pool](../../../src/Worker/Pool.py) | `DefStream.Pool` | 제출, 포화, 슬롯 반환, 완료 대기와 종료 |
|
|
23
|
+
| ThreadPool·ProcessPool | `DefStream.ThreadPool`·`DefStream.ProcessPool` | 구체 풀 구성과 상속받은 공통 동작 |
|
|
24
|
+
| [Executor](../../../src/Worker/Executor.py) | `DefStream.Executor` | 실행 환경 시작·종료, 작업·결과 전달과 실행 환경 장애 |
|
|
25
|
+
| [Run](../../../src/Worker/Run.py) | `DefStream.Run` | 작업 전체 이름, 훅·입출력 검증·실행 단계와 소요 시간 |
|
|
26
|
+
| [Inspector·Server·RequestHandler](../../../src/Inspector/Inspector.py) | `DefStream.Inspector` | 확장 등록·시작, 서버 생명주기, HTTP 수신·응답과 내부 오류 |
|
|
27
|
+
| [Inspector 확장](../../../src/Inspector/Extensions) | `DefStream.Inspector.Extensions.<클래스 이름>` | HealthCheck·Console·Metrics·Dashboard·Specifications의 고유 처리 |
|
|
28
|
+
|
|
29
|
+
ThreadPool·ProcessPool의 공통 처리는 구체 클래스의 로거로 기록한다.
|
|
30
|
+
`Specification`에는 독립 로거를 추가하지 않았다.
|
|
31
|
+
|
|
32
|
+
## 3. 레벨과 실패 처리
|
|
33
|
+
|
|
34
|
+
- INFO: Worker·풀·실행 환경·서버의 생명주기와 HTTP 응답 전송 결과.
|
|
35
|
+
- DEBUG: 메시지별 정상 처리, 작업 실행·검증·훅, 풀 포화와 확장 고유 진단.
|
|
36
|
+
- WARNING: 잘못된 메시지, 명시적 완료 대기의 시간 초과와 Console 요청 거부 등.
|
|
37
|
+
- ERROR: 작업·실행 환경·서버·확장 내부 실패와 종료 후 확인 처리 불가.
|
|
38
|
+
|
|
39
|
+
Worker로 전달되는 작업 실패의 최종 ERROR와 traceback은 Worker가 담당한다.
|
|
40
|
+
Run·Pool·Executor의 일반 작업 실패 추적은 DEBUG로 기록해 중복을 줄였다.
|
|
41
|
+
Mapping이 아닌 메시지의 거부는 WARNING으로 구분하고 기존 실패 정책 호출은 유지했다.
|
|
42
|
+
Run을 직접 호출했을 때의 예외 전파도 유지한다.
|
|
43
|
+
|
|
44
|
+
## 4. Inspector의 HTTP 기록
|
|
45
|
+
|
|
46
|
+
기본 WSGI 요청 처리 경계를 확장하여 다음을 기록한다.
|
|
47
|
+
|
|
48
|
+
- 파싱한 요청 수신: DEBUG, HTTP 메서드와 쿼리를 제외한 경로.
|
|
49
|
+
- 응답 전송 결과: INFO, 메서드·경로·상태 코드·응답 크기·소요 시간.
|
|
50
|
+
- WSGI·연결 처리 실패: ERROR, 예외 타입과 프레임의 파일·줄·함수 위치.
|
|
51
|
+
|
|
52
|
+
확장에서는 공통 HTTP 접근 로그를 반복하지 않는다. 전송 중단을 정상 전송으로
|
|
53
|
+
기록하지 않으며, 오류 기록에는 예외 문자열과 소스 코드 줄을 포함하지 않는다.
|
|
54
|
+
HealthCheck는 probe 예약·응답·판정과 응답 생성을 DEBUG로 기록하고,
|
|
55
|
+
예약 실패를 ERROR로 기록한다. 상태 변화 전용 INFO·WARNING은 추가하지 않았다.
|
|
56
|
+
|
|
57
|
+
## 5. 출력 설정과 샘플
|
|
58
|
+
|
|
59
|
+
- 라이브러리는 핸들러·NullHandler·포매터·필터·레벨을 설정하지 않는다.
|
|
60
|
+
- 루트 로거까지 기본 전파를 유지하며, 미설정 시 표준 `logging.lastResort`가
|
|
61
|
+
WARNING 이상을 stderr에 출력할 수 있다.
|
|
62
|
+
- 런타임 로그 메시지는 영어로 작성하고 한국어 문서·주석은 유지한다.
|
|
63
|
+
- 본문·결과·인증정보를 기본 문맥에 넣지 않는다. 단, Worker의 작업 실패
|
|
64
|
+
traceback에는 사용자 예외 메시지가 포함될 수 있으므로 사용자가 주의해야 한다.
|
|
65
|
+
- [Worker 샘플](../../../sample/Worker)과 [Broker 샘플](../../../sample/Broker)은
|
|
66
|
+
`Sample`과 `DefStream` 계층만 핸들러 필터로 선택한다.
|
|
67
|
+
- 샘플의 `print()`는 로그로 전환하고 라이브러리 시작 배너는 유지했다.
|
|
68
|
+
- [RabbitMQ Worker 샘플](../../../sample/Worker/RabbitMQ/Worker.py)은 부모 진입점과
|
|
69
|
+
ProcessPool의 `setups`에 [LoggingSetup](../../../sample/Worker/RabbitMQ/Tasks.py)을
|
|
70
|
+
적용한다. `spawn` 자식이 부모의 핸들러를 자동 상속한다고 가정하지 않는다.
|
|
71
|
+
|
|
72
|
+
## 6. 검증 결과
|
|
73
|
+
|
|
74
|
+
Python 3.13.16에서 실제 RabbitMQ·Redis가 실행 중인 환경으로 검증했다.
|
|
75
|
+
|
|
76
|
+
| 검증 범위 | 결과 |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| 코어 로깅·Inspector·Worker·풀·훅·프로세스·메시지 관련 테스트 | 151개 통과 |
|
|
79
|
+
| RabbitMQ 연계 테스트 | 52개 통과 |
|
|
80
|
+
| Redis 연계 테스트 | 25개 통과 |
|
|
81
|
+
| 세 프로젝트 소스·샘플의 로그 및 observe 호출 문자열 | 376곳 점검, 한국어 문자열 없음 |
|
|
82
|
+
| 세 프로젝트 소스·샘플 `compileall` 및 `git diff --check` | 통과 |
|
|
83
|
+
|
|
84
|
+
[로깅 테스트](../../../test/test_logging.py)는 클래스 멤버·상속·사용자 재정의,
|
|
85
|
+
레벨·본문 제외·작업 실패 traceback 중복 방지·배너 유지·샘플 필터·spawn 설정을
|
|
86
|
+
검증한다. [Inspector 로깅 테스트](../../../test/test_inspector_logging.py)는 실제 HTTP
|
|
87
|
+
요청에서 수신·응답 각 1회 기록, 쿼리·본문 제외, WSGI 500과 전송 중단을 검증한다.
|
|
88
|
+
기존 테스트의 이전 모듈 로거 기대값도 새 이름과 레벨에 맞췄다.
|
|
89
|
+
|
|
90
|
+
위 228개는 선택해 실행한 관련 테스트의 합계이며 코어 전체 테스트 실행을 뜻하지 않는다.
|
|
91
|
+
모든 Python 버전·모든 파일의 정적 타입 검사나 배포 검증을 완료한 것은 아니다.
|
|
92
|
+
|
|
93
|
+
### 재검증
|
|
94
|
+
|
|
95
|
+
개발 가상환경과 로컬 브로커가 준비된 작업공간 루트에서 실행한다.
|
|
96
|
+
통합 테스트는 브로커에 테스트 자원을 생성·정리하므로 운영 환경을 사용하지 않는다.
|
|
97
|
+
|
|
98
|
+
```powershell
|
|
99
|
+
$env:PYTHONIOENCODING = 'utf-8'
|
|
100
|
+
$env:DEFSTREAM_RABBITMQ_TESTS = '1'
|
|
101
|
+
$env:DEFSTREAM_REDIS_TESTS = '1'
|
|
102
|
+
Set-Location .\DefStream\test
|
|
103
|
+
& ..\..\.venv\Scripts\python.exe -m unittest test_logging test_inspector_logging test_worker test_worker_startup test_pool_callbacks test_runner_hooks test_lifecycle_hooks test_process_signals test_inspector test_inspector_console test_dashboard test_specifications test_protocol_contracts test_task_messages
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
브로커별 재검증 명령은 각 구현 기록을 참고한다.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# 로깅 지원
|
|
2
|
+
|
|
3
|
+
## 변경 요약
|
|
4
|
+
|
|
5
|
+
Worker와 Inspector의 동작을 클래스별 표준 로거로 관찰할 수 있습니다.
|
|
6
|
+
라이브러리는 로그를 기록하며, 출력 대상·형식·레벨·필터는 애플리케이션이 정합니다.
|
|
7
|
+
런타임 로그 메시지는 영어입니다.
|
|
8
|
+
|
|
9
|
+
## 추가한 기록
|
|
10
|
+
|
|
11
|
+
- `DefStream.Worker`: 등록·시작·수신·완료·실패·종료.
|
|
12
|
+
- `DefStream.Run`: 작업별 훅·입출력 검증·실행 단계.
|
|
13
|
+
- `DefStream.Pool`, `DefStream.ThreadPool`, `DefStream.ProcessPool`,
|
|
14
|
+
`DefStream.Executor`: 실행 환경·제출·결과 회수·대기·종료.
|
|
15
|
+
- `DefStream.Inspector`: 서버 생명주기, 요청 수신(DEBUG), 응답 상태·크기·시간(INFO).
|
|
16
|
+
- `DefStream.Inspector.Extensions.<클래스 이름>`: 각 확장 고유 진단.
|
|
17
|
+
|
|
18
|
+
정상 메시지별 상세 흐름은 DEBUG, 주요 생명주기는 INFO로 확인할 수 있습니다.
|
|
19
|
+
잘못된 메시지와 대기 시간 초과는 WARNING, 작업·내부 처리 실패는 ERROR로 구분합니다.
|
|
20
|
+
Pool 공통 동작도 실제 ThreadPool·ProcessPool의 로거 이름으로 기록됩니다.
|
|
21
|
+
|
|
22
|
+
## 사용자 설정과 호환성
|
|
23
|
+
|
|
24
|
+
- 기존 `DefStream.Worker.Worker` 등 모듈 경로 기반 이름으로 필터링했다면
|
|
25
|
+
새 클래스별 이름으로 바꾸세요. `DefStream` 계층 전체 수신도 가능합니다.
|
|
26
|
+
- 클래스 멤버 `logger`를 상속하며 사용자 하위 클래스에서 재정의할 수 있습니다.
|
|
27
|
+
사용자 작업이 직접 생성한 로거 이름은 프레임워크가 바꾸지 않습니다.
|
|
28
|
+
- 핸들러·NullHandler·레벨을 자동 설정하지 않습니다.
|
|
29
|
+
핸들러가 없으면 Python의 `lastResort`로 WARNING 이상이 출력될 수 있습니다.
|
|
30
|
+
- 본문·결과·인증정보는 기본 로그 문맥에서 제외합니다. 사용자 예외 메시지는
|
|
31
|
+
Worker의 실패 traceback에 포함될 수 있으므로 민감정보를 넣지 마세요.
|
|
32
|
+
- 작업 처리·정산·종료 계약과 기존 시작 배너는 유지합니다.
|
|
33
|
+
|
|
34
|
+
## 샘플 변경
|
|
35
|
+
|
|
36
|
+
샘플은 `print()` 대신 `Sample` 로거를 사용하며 `Sample`과 `DefStream` 계층만
|
|
37
|
+
출력합니다. [RabbitMQ Worker 샘플](../../../sample/Worker/RabbitMQ/Worker.py)은
|
|
38
|
+
부모와 spawn 자식에 [LoggingSetup](../../../sample/Worker/RabbitMQ/Tasks.py)을 적용합니다.
|
|
39
|
+
실제 애플리케이션도 ProcessPool 자식의 로깅을 별도로 설정해야 합니다.
|
|
40
|
+
설정 예제는 [사용 설명서](../../../README.md#로깅)를 참고하세요.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# 로깅 지원
|
|
2
|
+
|
|
3
|
+
## 1. 목적과 범위
|
|
4
|
+
|
|
5
|
+
- 개발자가 Worker의 시작부터 작업 실행, 메시지 완료 처리, 종료까지 추적할 수 있도록 풍부한 진단 로그를 제공한다.
|
|
6
|
+
- Inspector 및 확장의 시작, HTTP 요청 처리, 상태 확인과 내부 실패를 관찰할 수 있게 한다.
|
|
7
|
+
- Python 표준 `logging`을 사용하며, 출력 대상·형식·레벨·필터는 사용자 애플리케이션이 결정한다.
|
|
8
|
+
- 이 문서는 현재 소스 조사와 사용자 검토를 반영한 요구사항이다. 클래스별 로거 이름과 HTTP 기록 책임은 아래와 같이 확정한다.
|
|
9
|
+
- 이 요구사항에 따라 소스와 샘플의 로깅을 구현한다. 라이브러리용 로깅 초기화 API와 사용자용 `LOG_*` 함수는 범위에 포함하지 않는다.
|
|
10
|
+
- 브로커 구현체는 별도 명세를 따른다.
|
|
11
|
+
- [DefStream-RabbitMQ 로깅 지원](../../../../DefStream-RabbitMQ/issues/feature/5/REQUIREMENTS.md)
|
|
12
|
+
- [DefStream-Redis 로깅 지원](../../../../DefStream-Redis/issues/feature/5/REQUIREMENTS.md)
|
|
13
|
+
|
|
14
|
+
## 2. 로거 이름과 사용자 설정
|
|
15
|
+
|
|
16
|
+
- 모듈 경로를 그대로 사용하는 `getLogger(__name__)` 대신, 클래스마다 명시적으로 정한 고정 이름을 사용한다.
|
|
17
|
+
- 로거는 클래스 멤버로 보관한다. 기반 클래스의 공통 메서드는 해당 멤버를 사용하고, 구체 클래스는 필요한 경우 자신의 명시적 로거 멤버를 정의한다.
|
|
18
|
+
- Worker 계열 이름은 `DefStream.ClassName` 형식이다.
|
|
19
|
+
- Inspector·Server·RequestHandler는 `DefStream.Inspector` 이름을 공유한다.
|
|
20
|
+
- 내장 확장은 `DefStream.Inspector.Extensions.ExtensionName` 형식이다.
|
|
21
|
+
- 프레임워크 로그의 이름을 사용자 정의 하위 클래스의 모듈·클래스 이름으로 자동 변경하지 않는다.
|
|
22
|
+
- 사용자 `SendEmail`이 `Run`을 상속해도 기반 실행 흐름 로그는 `DefStream.Run`으로 기록한다.
|
|
23
|
+
- 실제 작업의 `모듈명.클래스명`은 별도 문맥으로 남겨 작업들을 구분한다.
|
|
24
|
+
- 사용자 정의 작업에서 직접 호출한 로깅의 이름·동작은 변경하지 않는다.
|
|
25
|
+
- 샘플은 `Sample` 로거를 사용하고, 샘플에서 설정한 출력 핸들러는 `Sample`과 `DefStream` 계층만 수신한다. 샘플의 `print()`는 DEBUG·INFO 로그로 대체하되 라이브러리의 시작 배너는 유지한다.
|
|
26
|
+
- 클래스별 이름과 상위 `DefStream`, `DefStream.Inspector`에서 선택적으로 수신할 수 있어야 한다.
|
|
27
|
+
- 루트 로거로의 기본 전파를 막지 않으며, 라이브러리가 `basicConfig()`, 출력 핸들러, 포매터, 필터, 로그 레벨을 임의로 설정하지 않는다.
|
|
28
|
+
- DefStream은 로그 기록만 수행하며 출력 핸들러뿐 아니라 `NullHandler`도 추가하지 않는다. 로그 수신·출력 설정은 사용자 애플리케이션의 책임이다.
|
|
29
|
+
- 사용자가 핸들러를 설정하지 않으면 Python 표준 동작인 `logging.lastResort`에 의해 WARNING 이상이 stderr에 출력될 수 있다. 이번 요구사항은 미설정 상태의 완전한 무출력을 보장하지 않는다.
|
|
30
|
+
|
|
31
|
+
## 3. 현재 상태
|
|
32
|
+
|
|
33
|
+
- [Worker](../../../src/Worker/Worker.py)의 모듈 로거가 작업 실패, 미확인 메시지를 남긴 종료, 종료 후 메시지 확인 처리 불가를 ERROR로 기록한다.
|
|
34
|
+
- [Inspector](../../../src/Inspector/Inspector.py)의 모듈 로거가 HTTP 접근 기록을 INFO로, 서버 실행 실패를 예외 로그로 기록한다.
|
|
35
|
+
- [Console](../../../src/Inspector/Extensions/Console.py)은 인증·출처·입력 거부, RPC 실패, 내부 요청 처리 실패를 기록한다.
|
|
36
|
+
- [HealthCheck](../../../src/Inspector/Extensions/HealthCheck.py)는 상태 확인 작업 예약 실패를 예외 로그로 기록한다.
|
|
37
|
+
- 다른 Worker 모듈과 나머지 Inspector 확장에는 현재 직접적인 로깅 호출이 없다.
|
|
38
|
+
- [Startup](../../../src/Worker/Startup.py)은 로거 대신 `print()`로 시작 배너와 구성을 출력한다.
|
|
39
|
+
|
|
40
|
+
## 4. 클래스별 로거 이름
|
|
41
|
+
|
|
42
|
+
아래 이름을 사용한다. 확장은 고유한 내부 처리와 진단에 필요한 로그만 기록하며, 공통 HTTP 접근 기록을 반복하지 않는다.
|
|
43
|
+
|
|
44
|
+
| 구분 | 클래스와 소스 | 로거 이름 | 필요한 관찰 범위 |
|
|
45
|
+
| --- | --- | --- | --- |
|
|
46
|
+
| 우선 대상 | [Worker](../../../src/Worker/Worker.py) | `DefStream.Worker` | 등록·시작·수신·완료·실패·종료의 전체 조정 |
|
|
47
|
+
| 공통 구현 | [Pool](../../../src/Worker/Pool.py) | `DefStream.Pool` (직접 생성 시) | 제출 수락·포화·슬롯 반환·완료 대기를 기록하며, 내장 구체 풀에서는 구체 클래스의 로거 멤버를 사용 |
|
|
48
|
+
| 우선 대상 | [ThreadPool](../../../src/Worker/Pool.py) | `DefStream.ThreadPool` | 스레드 풀 구성 및 상속받은 Pool 공통 동작 |
|
|
49
|
+
| 우선 대상 | [ProcessPool](../../../src/Worker/Pool.py) | `DefStream.ProcessPool` | 프로세스 풀 구성 및 상속받은 Pool 공통 동작 |
|
|
50
|
+
| 우선 대상 | [Executor](../../../src/Worker/Executor.py) | `DefStream.Executor` | 실행 환경 시작·종료, 작업 전달·결과 회수, 실행 환경 장애 |
|
|
51
|
+
| 우선 대상 | [Run](../../../src/Worker/Run.py) | `DefStream.Run` | 사용자 작업을 감싸는 훅·검증·실행 단계 |
|
|
52
|
+
| 우선 대상 | [Inspector](../../../src/Inspector/Inspector.py) | `DefStream.Inspector` | 확장 등록·시작, HTTP 서버 생명주기와 요청 처리 |
|
|
53
|
+
| 보조 대상 | [Server](../../../src/Inspector/Inspector.py) | `DefStream.Inspector` (공유) | HTTP 서버의 연결 처리 문맥. Inspector와 중복되는 생명주기 로그는 제외 |
|
|
54
|
+
| 보조 대상 | [RequestHandler](../../../src/Inspector/Inspector.py) | `DefStream.Inspector` (공유) | 공통 HTTP 요청 수신(DEBUG)과 응답 상태를 포함한 전송 결과(INFO) |
|
|
55
|
+
| 우선 대상 | [HealthCheck](../../../src/Inspector/Extensions/HealthCheck.py) | `DefStream.Inspector.Extensions.HealthCheck` | 상태 확인 작업 예약·응답·시간 초과·상태 변화 |
|
|
56
|
+
| 우선 대상 | [Console](../../../src/Inspector/Extensions/Console.py) | `DefStream.Inspector.Extensions.Console` | 요청 검증·발행·RPC·접근 거부·내부 오류 |
|
|
57
|
+
| 우선 대상 | [Metrics](../../../src/Inspector/Extensions/Metrics.py) | `DefStream.Inspector.Extensions.Metrics` | 수집 초기화, 작업 관측 시작·종료, 스냅샷·응답 생성 |
|
|
58
|
+
| 우선 대상 | [Dashboard](../../../src/Inspector/Extensions/Dashboard.py) | `DefStream.Inspector.Extensions.Dashboard` | Metrics 연결, HTML·JSON 응답 생성 |
|
|
59
|
+
| 우선 대상 | [Specifications](../../../src/Inspector/Extensions/Specifications.py) | `DefStream.Inspector.Extensions.Specifications` | 작업 목록의 AsyncAPI 문서 생성과 응답 |
|
|
60
|
+
|
|
61
|
+
### 4.1. 독립 로거를 우선 추가하지 않을 대상
|
|
62
|
+
|
|
63
|
+
| 대상 | 판단 근거와 기록 책임 |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| [Specification](../../../src/Worker/Specification.py) | 독립 로깅 대상에서 제외한다. 입력·출력 검증 단계와 실패는 Run·Worker에서 관찰한다. Inspector의 Specifications 확장과는 별개이다. |
|
|
66
|
+
| [Handler](../../../src/Worker/Worker.py) | Worker의 `receive()`로 전달하는 어댑터이다. 수신 로그는 Worker에서 기록한다. |
|
|
67
|
+
| [WorkerSetup·WorkerCleanup](../../../src/Worker/Worker.py), [PoolSetup·PoolCleanup](../../../src/Worker/Pool.py), [RunSetup·RunComplete·RunError](../../../src/Worker/Run.py) | 사용자 구현용 추상 계약이다. 호출 전후를 프레임워크의 호출 지점에서 기록하며 구현체 내부 로그는 사용자가 정한다. |
|
|
68
|
+
| [Context](../../../src/Worker/Run.py), [PoolFull](../../../src/Worker/Pool.py) | 문맥 보관 객체와 예외 타입이다. 생성 자체를 별도 로깅하지 않는다. |
|
|
69
|
+
| [Extension](../../../src/Inspector/Extension.py) | 기본 훅은 동작이 없거나 구체 확장으로 위임한다. 등록·호출은 Inspector, 구체 동작은 해당 확장에서 기록한다. |
|
|
70
|
+
| [Response](../../../src/Inspector/Response.py), [TaskMetrics·스냅샷 타입](../../../src/Inspector/Extensions/Metrics.py) | 응답·집계·데이터 표현 객체이다. 생성이나 필드별 갱신을 별도 로거로 기록하지 않는다. |
|
|
71
|
+
| [Broker 계약](../../../src/Broker/Connection.py)과 [기본 Consumer](../../../src/Broker/Consumer.py) | 인터페이스 및 공통 위임이다. 실제 I/O 로그는 구현체에서 기록한다. |
|
|
72
|
+
| [Requeue·Reject](../../../src/Broker/Policies.py) | Event의 `nack()`·`reject()`로 위임한다. Worker/Consumer에서 정책 선택, 구현체 Event에서 실제 처리 결과를 기록한다. |
|
|
73
|
+
| [Descriptor](../../../src/Descriptor)·[Validator](../../../src/Validator) 계열 | 값 변환·검증의 세부 재귀 호출마다 로그를 추가하지 않는다. 작업 경계의 Run에서 단계와 실패를 추적한다. |
|
|
74
|
+
|
|
75
|
+
### 4.2. 클래스가 아닌 처리의 귀속
|
|
76
|
+
|
|
77
|
+
- [Startup.startup()](../../../src/Worker/Startup.py): 기존 `print()` 시작 배너와 구성 출력을 유지한다. 로그로 대체하거나 동일한 배너를 중복 로깅하지 않는다. Worker의 생명주기 로그는 별도로 기록한다.
|
|
78
|
+
- [Executor의 execute_loop()·initialize_process()](../../../src/Worker/Executor.py): 스레드·프로세스 내부 실행 로그는 `DefStream.Executor`에 귀속하는 후보로 둔다.
|
|
79
|
+
- [Executor의 run_cleanups()](../../../src/Worker/Executor.py): Worker 종료와 실행 환경 종료에서 함께 사용한다. 훅 호출 주체의 로거에서 기록하여 중복을 피한다.
|
|
80
|
+
- [Message의 declare()·emit()·request()](../../../src/Worker/Message.py): 클래스가 없는 공통 API이므로 새 클래스나 임의의 로거 이름을 만들지 않는다. 이번 초안에서는 실제 브로커 구현체와 Console 호출 지점에서 기록한다.
|
|
81
|
+
- Pool 공통 메서드의 `self`는 실제 ThreadPool·ProcessPool 인스턴스이므로 구체 풀에 명시적으로 지정한 로거를 사용한다. 두 내장 풀의 공통 동작이 `DefStream.Pool`로 기록되지 않도록 한다.
|
|
82
|
+
- 사용자 하위 클래스는 기반 ThreadPool·ProcessPool의 명시적 이름을 유지한다. 단순히 `type(self).__name__`으로 로거 이름을 자동 생성하지 않는다.
|
|
83
|
+
- Pool은 추상 클래스가 아니며 외부 executor를 받아 직접 생성할 수 있는 기존 공개 API이다. 클래스 멤버의 이름은 `DefStream.Pool`로 두고, ThreadPool·ProcessPool은 각각 자신의 명시적 로거 멤버를 정의한다. 별도 이름 판별·주입 API를 추가하지 않는다.
|
|
84
|
+
|
|
85
|
+
## 5. 레벨별 기록 요구사항
|
|
86
|
+
|
|
87
|
+
### 5.1. Worker
|
|
88
|
+
|
|
89
|
+
- INFO: 시작 시도, 구독을 마치고 수신 가능한 상태, 최초 종료 요청, 실행 중 작업 정리 대기, 실제 자원 정리를 마친 종료.
|
|
90
|
+
- DEBUG: 작업 등록, broker 연결·Consumer 생성 단계, setup·cleanup 호출 전후, 구독 적용, 메시지 수신, Pool 제출, 결과 콜백 예약, 성공·실패 정책 적용, 미완료 작업 수 변화.
|
|
91
|
+
- DEBUG: 종료 중 수신 메시지의 `nack()`, Pool 포화에 따른 `nack()` 등 정상 흐름 제어.
|
|
92
|
+
- WARNING: Mapping이 아닌 메시지 본문처럼 실행 전에 거부하는 잘못된 메시지. 해당 사건을 기존 ERROR 경로와 이중 기록하지 않는다.
|
|
93
|
+
- ERROR: 사용자 작업·훅·검증 실패, Consumer 종료 시 남은 미확인 메시지, Consumer 종료 후 결과 도착으로 확인 처리 불가.
|
|
94
|
+
- 완료 로그는 작업 실행 성공과 Consumer 완료 처리의 성공을 구분한다. 브로커 재전달·영속화까지 보장한 것처럼 표현하지 않는다.
|
|
95
|
+
|
|
96
|
+
### 5.2. Pool·ThreadPool·ProcessPool·Executor
|
|
97
|
+
|
|
98
|
+
- INFO: 구체 풀의 동시 실행 수와 실행 방식, Executor 실행 환경 시작·종료, Pool 종료 시작·완료.
|
|
99
|
+
- DEBUG: 작업 제출·회수, 내부 작업 키, 사용 슬롯·대기 작업 수, Future 완료, 결과·예외 전달 단계, 실행 단위별 setup·cleanup.
|
|
100
|
+
- DEBUG: 정상적인 풀 포화, 취소·미제출 등 기존 흐름상 발생 가능한 상태. 포화가 발생할 때마다 WARNING을 출력하지 않는다.
|
|
101
|
+
- WARNING: 명시적으로 요청한 완료 대기의 시간 초과. 정상적인 내부 큐 조회의 `Empty`는 경고가 아니다.
|
|
102
|
+
- ERROR: 실행 환경 시작 실패, 실행 단위 비정상 종료, 결과 수집 루프 장애, 작업 결과 직렬화 실패.
|
|
103
|
+
- 사용자 작업 예외를 Pool과 Executor에서도 반복 ERROR로 출력하지 않는다. Worker로 전달되는 경로에서는 최종 작업 실패 로그를 Worker가 담당한다.
|
|
104
|
+
- 프로세스 실행의 로그에는 프로세스 구분이 가능해야 한다. 부모의 핸들러 설정이 `spawn` 자식에게 자동으로 전달된다고 가정하지 않으며 기존 setup 훅을 이용한 자식 로깅 설정 방법을 문서화한다.
|
|
105
|
+
|
|
106
|
+
### 5.3. Run
|
|
107
|
+
|
|
108
|
+
- DEBUG: 작업의 전체 이름, setup·입력 검증·실행·출력 검증·complete/error 훅의 시작·완료·실패 단계.
|
|
109
|
+
- DEBUG: 실행 소요 시간은 시작과 종료의 대응이 가능한 범위에서 기록한다. Run 실행 시간과 Worker 전체 처리 시간은 구분한다.
|
|
110
|
+
- INFO: 메시지마다 반복되는 정상 실행 로그를 기본적으로 올리지 않는다.
|
|
111
|
+
- 작업 실패의 최종 ERROR와 traceback은 Worker에서 기록한다. Run 단계 로그는 실패가 발생한 위치를 식별하는 역할을 한다.
|
|
112
|
+
- Run을 Worker 밖에서 직접 실행했을 때는 예외가 기존대로 호출자에게 전파된다. 로깅을 위해 예외를 삼키지 않는다.
|
|
113
|
+
- 검증 대상 값, 스키마 전체, 예제 값은 출력하지 않는다.
|
|
114
|
+
|
|
115
|
+
### 5.4. Inspector·Server·RequestHandler
|
|
116
|
+
|
|
117
|
+
- INFO: 실제 바인딩된 주소·포트와 서버 시작·종료. 포트 `0`을 요청한 경우 실제 할당 포트를 기록한다.
|
|
118
|
+
- DEBUG: 확장 클래스·경로 등록, 확장 시작, 라우팅 대상 및 HTTP 요청 수신 시 메서드·안전한 경로.
|
|
119
|
+
- INFO: HTTP 응답 전송 결과를 상태 코드와 함께 기록한다. 가능한 경우 응답 크기·처리 시간도 포함한다. 모든 확장의 공통 접근 기록은 이 경계에서 담당한다.
|
|
120
|
+
- 응답 생성과 실제 전송 완료를 구분한다. 전송 도중 실패한 응답을 정상 전송 완료로 기록하지 않으며, 기본 WSGI 접근 기록과 추가 로그가 중복되지 않도록 한다.
|
|
121
|
+
- WARNING: 비정상 요청 거부는 HTTP 상태와 사유를 구분하되, 정상적인 404·405를 일괄 경고로 취급하지 않는다.
|
|
122
|
+
- ERROR: 서버 바인딩·실행 실패, 확장 시작·요청 처리 중 내부 오류. 이미 전파되는 예외의 의미와 Worker 중지 동작을 보존한다.
|
|
123
|
+
|
|
124
|
+
### 5.5. Inspector 확장
|
|
125
|
+
|
|
126
|
+
| 클래스 | INFO | DEBUG | WARNING / ERROR |
|
|
127
|
+
| --- | --- | --- | --- |
|
|
128
|
+
| HealthCheck | 관측 상태 변화와 복구만 기록하는 후보 | probe 예약·응답·시간 초과, 판정 상태 | 정상 실행 중 응답 불가 전환은 WARNING 후보, 예약 중 예외는 ERROR. 정상 시작·종료 상태의 503은 장애와 구분 |
|
|
129
|
+
| Console | 초기화 및 관리용 작업 발행·RPC 요청의 접수·성공 요약 | 카탈로그 생성, producer 생성·연결·정리, 작업·모드·소요 시간 | 인증·출처·입력 거부, 동시 요청 제한, RPC 시간 초과·원격 오류는 WARNING. 내부 요청 처리 실패는 ERROR |
|
|
130
|
+
| Metrics | 수집 초기화와 관측 대상 작업 수 | 작업 관측 시작·종료, 스냅샷·렌더링 요약 | 집계·렌더링 내부 오류. 측정 대상 작업 실패를 Metrics에서 다시 ERROR로 출력하지 않음 |
|
|
131
|
+
| Dashboard | Metrics 확장 연결 | HTML·JSON 응답 생성·소요 시간 | 필수 Metrics 연결 실패, 리소스 읽기·응답 생성 실패 |
|
|
132
|
+
| Specifications | 확장 시작 시 경로 등 등록 요약은 Inspector가 담당 | 문서 생성 시작·완료, 작업·채널 수 | 중복 식별자·주소 오류·스키마 문서 생성 실패 |
|
|
133
|
+
|
|
134
|
+
- 매번 같은 실패 상태를 반복하는 probe나 HTTP 조회로 WARNING·ERROR가 무제한 반복되지 않도록 기록 지점과 빈도를 검토한다.
|
|
135
|
+
- 표의 오류는 각 클래스의 관찰 대상이다. 공통 Inspector 경계에서 기록한다면 동일 예외를 확장에서도 다시 ERROR로 기록하지 않는다.
|
|
136
|
+
- 공통 HTTP 수신·응답 기록은 확장에서 반복하지 않는다. 단순 응답 생성이라는 이유만으로 독립 로그를 의무화하지 않고 확장 고유의 처리 단계가 있을 때 DEBUG를 기록한다.
|
|
137
|
+
|
|
138
|
+
## 6. 기록 품질과 호환성
|
|
139
|
+
|
|
140
|
+
- 공개 라이브러리와 샘플의 런타임 로그 메시지는 영어로 작성한다. 한국어 문서·주석은 유지하고 API·클래스·작업 식별자는 원문을 유지한다.
|
|
141
|
+
- 최소 문맥은 사건명, 처리 단계, 작업의 전체 이름이며 해당 시점에 실제로 알 수 있는 값만 기록한다.
|
|
142
|
+
- 메시지 식별자가 필요한 경우 브로커별 속성을 임의로 가정하지 않는다. 공통 Event 계약을 확장할지는 별도 결정하며, 현 단계에서는 가짜 식별자를 만들지 않는다.
|
|
143
|
+
- 비밀번호, 인증 토큰·다이제스트, 전체 연결 설정, 메시지 본문, 결과 값, HTTP 요청 본문·헤더 전체, 쿼리 문자열을 기록하지 않는다.
|
|
144
|
+
- 객체의 `repr()`나 예외 문자열에 본문·인증정보가 포함될 수 있으므로 무조건 출력하지 않는다. traceback 기록도 예외 메시지에 민감정보가 포함될 가능성을 검토한다.
|
|
145
|
+
- 같은 예외의 traceback은 한 처리 경계에서 기록한다. 예외를 로깅하기 위해 추가한 포착 구문은 기존 전파·정리·재시도 동작을 바꾸지 않는다.
|
|
146
|
+
- DEBUG 비활성 상태에서 로그만을 위한 직렬화·전체 순회·추가 I/O를 하지 않는다. 메시지 치환은 지연 평가를 활용한다.
|
|
147
|
+
- 로그 추가를 이유로 제출 순서, 슬롯 반환, ack/nack/reject, 종료 대기, 훅 실행 횟수, 스레드·프로세스 소유권을 바꾸지 않는다.
|
|
148
|
+
|
|
149
|
+
## 7. 확정 사항과 구현 원칙
|
|
150
|
+
|
|
151
|
+
1. `print()` 시작 배너와 구성 출력을 유지한다.
|
|
152
|
+
2. 로거는 클래스 멤버로 보관하고, Pool 공통 동작은 구체 클래스의 로거 멤버로 기록한다. 직접 생성한 Pool은 `DefStream.Pool`을 사용한다.
|
|
153
|
+
3. 상태 확인 반복 실패의 빈도 제어는 중복·과도한 출력 방지 원칙에 따라 구현 시 구체화한다. 별도 설정 API를 미리 추가하지 않는다.
|
|
154
|
+
4. 핸들러 주입·로거 교체 API를 추가하지 않으며, 명시적 이름과 상속 시 이름 유지 계약을 지킨다.
|
|
155
|
+
|
|
156
|
+
## 8. 구현 후 수용 기준
|
|
157
|
+
|
|
158
|
+
- 확정된 각 클래스 이름으로 LogRecord가 생성되고, 사용자 Run 하위 클래스 때문에 프레임워크 로거 이름이 달라지지 않는다.
|
|
159
|
+
- ThreadPool·ProcessPool의 상속받은 공통 메서드도 각각 `DefStream.ThreadPool`·`DefStream.ProcessPool`로 기록하며 사용자 하위 클래스에서도 명시적 이름을 유지한다.
|
|
160
|
+
- Inspector·Server·RequestHandler가 `DefStream.Inspector`를 공유하고, 요청 수신은 DEBUG, 응답 전송 결과와 상태 코드는 INFO로 한 번씩 기록한다.
|
|
161
|
+
- Specification에 독립 로거를 추가하지 않는다.
|
|
162
|
+
- 기존 `print()` 시작 배너·구성 출력의 내용과 동작을 유지하고, 로그 설정 여부로 이를 비활성화하지 않는다.
|
|
163
|
+
- Worker 정상 처리·실패·풀 포화·종료, Executor 실행 환경 장애, Inspector 및 확장 정상·실패 경로의 레벨과 문맥을 검사한다.
|
|
164
|
+
- `DefStream` 상위 로거 및 루트 핸들러에서 전파를 수신하고, 클래스·확장별 설정으로 선택 수신할 수 있다.
|
|
165
|
+
- 사용자 핸들러·레벨·필터·포매터를 임의로 변경하지 않고, DefStream이 출력 핸들러 또는 NullHandler를 추가하지 않는다.
|
|
166
|
+
- INFO에서 메시지별 DEBUG 로그가 나오지 않으며, 정상 포화·폴링·시작 및 종료 상태가 경고로 반복 출력되지 않는다.
|
|
167
|
+
- 동일 실패의 중복 traceback과 민감정보 누출이 없고, 기존 Worker·Pool·Run·Inspector 테스트가 보장하는 동작을 유지한다.
|
|
168
|
+
- ProcessPool의 부모·자식 로그 수집 조건과 설정 예제를 문서화하고, 프로세스별 로깅 설정을 적용한 경우를 검증한다.
|