pam-python 0.1.40__tar.gz → 0.1.41__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.
- {pam_python-0.1.40/pam_python.egg-info → pam_python-0.1.41}/PKG-INFO +1 -1
- pam_python-0.1.41/pam/logger.py +96 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/models/request_command.py +5 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/utils.py +2 -3
- {pam_python-0.1.40 → pam_python-0.1.41/pam_python.egg-info}/PKG-INFO +1 -1
- {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/SOURCES.txt +1 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/setup.py +1 -1
- {pam_python-0.1.40 → pam_python-0.1.41}/LICENSE.txt +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/README.md +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/__init__.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/api.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/cli.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/interface_task_manager.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/models/__init__.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/request_file_format.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/server.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/service.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/sqlite.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/task_manager.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/temp_file_utils.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/buildcmd/pamb +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/buildcmd/pamb-base.sh +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/docker/Dockerfile +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/AGENT.md +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/dockerignore.tmpl +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/gitignore.tmpl +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/main.tmpl +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/pylintrc.tmpl +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/run_unit_test.bat +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/run_unit_test.ps1 +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/init/run_unit_test.sh +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/service/functions.tmpl +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/service/service.test.tmpl +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/service/service.yaml +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/templates/service/service_class.tmpl +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam/tester_task.py +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/dependency_links.txt +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/entry_points.txt +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/requires.txt +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/pam_python.egg-info/top_level.txt +0 -0
- {pam_python-0.1.40 → pam_python-0.1.41}/setup.cfg +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from threading import Lock
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pam.utils import log as stdout_log
|
|
8
|
+
from service import Service
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Logger:
|
|
12
|
+
def __init__(self, service: Service, buffer_size: int = 20, source: str = "worker"):
|
|
13
|
+
self.service = service
|
|
14
|
+
self.log_api = service.request.log_api
|
|
15
|
+
self.token = service.request.token
|
|
16
|
+
self.source = source
|
|
17
|
+
self.buffer_size = max(1, int(buffer_size))
|
|
18
|
+
self._buffer: list[dict[str, Any]] = []
|
|
19
|
+
self._lock = Lock()
|
|
20
|
+
|
|
21
|
+
def debug(self, message: Any, stage: str = "") -> None:
|
|
22
|
+
self.log(message, level="debug", stage=stage)
|
|
23
|
+
|
|
24
|
+
def info(self, message: Any, stage: str = "") -> None:
|
|
25
|
+
self.log(message, level="info", stage=stage)
|
|
26
|
+
|
|
27
|
+
def warning(self, message: Any, stage: str = "") -> None:
|
|
28
|
+
self.log(message, level="warning", stage=stage)
|
|
29
|
+
|
|
30
|
+
def error(self, message: Any, stage: str = "") -> None:
|
|
31
|
+
self.log(message, level="error", stage=stage)
|
|
32
|
+
|
|
33
|
+
def log(self, message: Any, level: str = "info", stage: str = "") -> None:
|
|
34
|
+
message_str = self._stringify(message)
|
|
35
|
+
self._write_stdout(message_str, level)
|
|
36
|
+
should_flush = self._enqueue(self._build_log_item(message_str, level, stage))
|
|
37
|
+
|
|
38
|
+
if should_flush:
|
|
39
|
+
self.flush()
|
|
40
|
+
|
|
41
|
+
def flush(self) -> bool:
|
|
42
|
+
if not self.log_api or not self.token:
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
with self._lock:
|
|
46
|
+
if not self._buffer:
|
|
47
|
+
return True
|
|
48
|
+
logs = list(self._buffer)
|
|
49
|
+
|
|
50
|
+
payload = {
|
|
51
|
+
"token": self.token,
|
|
52
|
+
"logs": logs,
|
|
53
|
+
}
|
|
54
|
+
response = self.service.task_manager.api.http_post(self.log_api, payload)
|
|
55
|
+
if response is None:
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
with self._lock:
|
|
59
|
+
if self._buffer[:len(logs)] == logs:
|
|
60
|
+
del self._buffer[:len(logs)]
|
|
61
|
+
else:
|
|
62
|
+
self._buffer = self._buffer[len(logs):]
|
|
63
|
+
return True
|
|
64
|
+
|
|
65
|
+
def pending_count(self) -> int:
|
|
66
|
+
with self._lock:
|
|
67
|
+
return len(self._buffer)
|
|
68
|
+
|
|
69
|
+
def _write_stdout(self, message: str, level: str) -> None:
|
|
70
|
+
stdout_log(f"[{level}] {message}")
|
|
71
|
+
|
|
72
|
+
def _build_log_item(self, message: str, level: str, stage: str) -> dict[str, Any]:
|
|
73
|
+
log_item = {
|
|
74
|
+
"message": message,
|
|
75
|
+
"level": level,
|
|
76
|
+
"source": self.source,
|
|
77
|
+
"logged_at": self._utc_now(),
|
|
78
|
+
}
|
|
79
|
+
if stage:
|
|
80
|
+
log_item["stage"] = stage
|
|
81
|
+
return log_item
|
|
82
|
+
|
|
83
|
+
def _enqueue(self, log_item: dict[str, Any]) -> bool:
|
|
84
|
+
with self._lock:
|
|
85
|
+
self._buffer.append(log_item)
|
|
86
|
+
return len(self._buffer) >= self.buffer_size
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def _stringify(message: Any) -> str:
|
|
90
|
+
if isinstance(message, str):
|
|
91
|
+
return message
|
|
92
|
+
return str(message)
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def _utc_now() -> str:
|
|
96
|
+
return datetime.now(timezone.utc).isoformat(timespec="milliseconds")
|
|
@@ -43,6 +43,7 @@ class RequestCommand:
|
|
|
43
43
|
next: str
|
|
44
44
|
input_files: list[str]
|
|
45
45
|
service_name: str
|
|
46
|
+
log_api: str
|
|
46
47
|
|
|
47
48
|
def is_start_command(self):
|
|
48
49
|
"""Determine if this command is a start command."""
|
|
@@ -138,6 +139,9 @@ class RequestCommand:
|
|
|
138
139
|
sqlite_download = params.pop("sqlite_download", "")
|
|
139
140
|
|
|
140
141
|
response_api = params.pop("response", "")
|
|
142
|
+
|
|
143
|
+
log_api = params.pop("log", "")
|
|
144
|
+
|
|
141
145
|
is_end = RequestCommand.__safe_str_to_bool(params.pop("is_end", "true"))
|
|
142
146
|
next_page = params.pop("next", "")
|
|
143
147
|
|
|
@@ -167,4 +171,5 @@ class RequestCommand:
|
|
|
167
171
|
next=next_page,
|
|
168
172
|
input_files=input_files,
|
|
169
173
|
service_name=service_name,
|
|
174
|
+
log_api=log_api
|
|
170
175
|
), error_message
|
|
@@ -5,7 +5,6 @@ import re
|
|
|
5
5
|
import pytz
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
def get_adapter_id(url: str) -> str:
|
|
10
9
|
"""
|
|
11
10
|
Extracts the adapter ID from a given URL.
|
|
@@ -55,6 +54,6 @@ def log(msg: str, level: str = "INFO"):
|
|
|
55
54
|
tz = pytz.timezone('Asia/Bangkok')
|
|
56
55
|
bangkok_time = utc_dt.astimezone(tz) # Convert UTC time to Bangkok time
|
|
57
56
|
date_str = bangkok_time.strftime("%m/%d/%Y %H:%M:%S")
|
|
58
|
-
print(f"[{date_str}] [{level}]: {msg}")
|
|
57
|
+
print(f"[{date_str}] [{level}]: {msg}", flush=True)
|
|
59
58
|
except Exception as e:
|
|
60
|
-
print(f"Failed to log message: {msg}. Error: {e}")
|
|
59
|
+
print(f"Failed to log message: {msg}. Error: {e}", flush=True)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|