dd-logging 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 digital-duck
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.
@@ -0,0 +1,123 @@
1
+ Metadata-Version: 2.4
2
+ Name: dd-logging
3
+ Version: 0.1.0
4
+ Summary: Shared logging helpers for Digital Duck projects (spl-llm, spl-flow, …)
5
+ Author-email: Wen Gong <wen.gong.research@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/digital-duck/dd-logging
8
+ Project-URL: Repository, https://github.com/digital-duck/dd-logging
9
+ Project-URL: Issues, https://github.com/digital-duck/dd-logging/issues
10
+ Keywords: logging,digital-duck,spl
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: System :: Logging
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Dynamic: license-file
22
+
23
+ # dd-logging
24
+
25
+ Shared logging helpers for [Digital Duck](https://github.com/digital-duck) projects.
26
+
27
+ Provides a consistent, timestamped-file logging pattern for CLI tools and Streamlit apps.
28
+ Used by **spl-llm** and **spl-flow**; designed to be reused by any project in the ecosystem.
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ # from PyPI (once published)
34
+ pip install dd-logging
35
+
36
+ # local editable install (for development)
37
+ pip install -e /path/to/dd-logging
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ ```python
43
+ from dd_logging import setup_logging, get_logger, disable_logging
44
+
45
+ # 1. Call once per process (CLI entry point or app startup)
46
+ log_path = setup_logging(
47
+ "run",
48
+ root_name="my_app", # top-level logger namespace
49
+ adapter="openrouter", # appended to filename (optional)
50
+ log_level="info", # debug | info | warning | error
51
+ )
52
+ # → logs/run-openrouter-20260215-143022.log
53
+
54
+ # 2. In each module
55
+ _log = get_logger("nodes.text2spl", root_name="my_app")
56
+ _log.info("translating query len=%d", len(query))
57
+
58
+ # 3. Silence all logging (e.g. --no-log CLI flag)
59
+ disable_logging("my_app")
60
+ ```
61
+
62
+ ### Thin wrapper pattern (recommended)
63
+
64
+ Each project wraps `dd_logging` so call-sites never pass `root_name`:
65
+
66
+ ```python
67
+ # myapp/logging_config.py
68
+ from pathlib import Path
69
+ from dd_logging import setup_logging as _setup, get_logger as _get, disable_logging as _disable
70
+
71
+ _ROOT = "my_app"
72
+ LOG_DIR = Path(__file__).resolve().parent.parent / "logs"
73
+
74
+ def get_logger(name: str):
75
+ return _get(name, _ROOT)
76
+
77
+ def setup_logging(run_name: str, **kw):
78
+ kw.setdefault("log_dir", LOG_DIR)
79
+ return _setup(run_name, root_name=_ROOT, **kw)
80
+
81
+ def disable_logging():
82
+ return _disable(_ROOT)
83
+ ```
84
+
85
+ ## Log file naming
86
+
87
+ ```
88
+ <log_dir>/<run_name>[-<adapter>]-<YYYYMMDD-HHMMSS>.log
89
+
90
+ logs/run-openrouter-20260215-143022.log
91
+ logs/benchmark-claude_cli-20260215-144500.log
92
+ logs/generate-20260215-145001.log
93
+ ```
94
+
95
+ ## Logger hierarchy
96
+
97
+ ```
98
+ my_app ← root (FileHandler attached here)
99
+ ├── my_app.api ← get_logger("api", "my_app")
100
+ ├── my_app.nodes.text2spl ← get_logger("nodes.text2spl", "my_app")
101
+ └── my_app.flows ← get_logger("flows", "my_app")
102
+ ```
103
+
104
+ All child loggers inherit the root's handler — no per-module handler setup needed.
105
+
106
+ ## Design notes
107
+
108
+ - **`propagate=False`** — prevents duplicate output when a root Python logger
109
+ handler is already configured (e.g. Streamlit, pytest, Jupyter).
110
+ - **Stale-handler removal** — calling `setup_logging()` multiple times in one
111
+ process (e.g. test suites) is safe; old `FileHandler`s are replaced.
112
+ - **No third-party dependencies** — stdlib `logging` only.
113
+
114
+ ## Projects using dd-logging
115
+
116
+ | Project | Root name | Log dir |
117
+ |---------|-----------|---------|
118
+ | [spl-llm](https://github.com/digital-duck/SPL) | `spl` | `SPL/logs/` |
119
+ | [spl-flow](https://github.com/digital-duck/SPL-Flow) | `spl_flow` | `SPL-Flow/logs/` |
120
+
121
+ ## License
122
+
123
+ MIT
@@ -0,0 +1,101 @@
1
+ # dd-logging
2
+
3
+ Shared logging helpers for [Digital Duck](https://github.com/digital-duck) projects.
4
+
5
+ Provides a consistent, timestamped-file logging pattern for CLI tools and Streamlit apps.
6
+ Used by **spl-llm** and **spl-flow**; designed to be reused by any project in the ecosystem.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ # from PyPI (once published)
12
+ pip install dd-logging
13
+
14
+ # local editable install (for development)
15
+ pip install -e /path/to/dd-logging
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```python
21
+ from dd_logging import setup_logging, get_logger, disable_logging
22
+
23
+ # 1. Call once per process (CLI entry point or app startup)
24
+ log_path = setup_logging(
25
+ "run",
26
+ root_name="my_app", # top-level logger namespace
27
+ adapter="openrouter", # appended to filename (optional)
28
+ log_level="info", # debug | info | warning | error
29
+ )
30
+ # → logs/run-openrouter-20260215-143022.log
31
+
32
+ # 2. In each module
33
+ _log = get_logger("nodes.text2spl", root_name="my_app")
34
+ _log.info("translating query len=%d", len(query))
35
+
36
+ # 3. Silence all logging (e.g. --no-log CLI flag)
37
+ disable_logging("my_app")
38
+ ```
39
+
40
+ ### Thin wrapper pattern (recommended)
41
+
42
+ Each project wraps `dd_logging` so call-sites never pass `root_name`:
43
+
44
+ ```python
45
+ # myapp/logging_config.py
46
+ from pathlib import Path
47
+ from dd_logging import setup_logging as _setup, get_logger as _get, disable_logging as _disable
48
+
49
+ _ROOT = "my_app"
50
+ LOG_DIR = Path(__file__).resolve().parent.parent / "logs"
51
+
52
+ def get_logger(name: str):
53
+ return _get(name, _ROOT)
54
+
55
+ def setup_logging(run_name: str, **kw):
56
+ kw.setdefault("log_dir", LOG_DIR)
57
+ return _setup(run_name, root_name=_ROOT, **kw)
58
+
59
+ def disable_logging():
60
+ return _disable(_ROOT)
61
+ ```
62
+
63
+ ## Log file naming
64
+
65
+ ```
66
+ <log_dir>/<run_name>[-<adapter>]-<YYYYMMDD-HHMMSS>.log
67
+
68
+ logs/run-openrouter-20260215-143022.log
69
+ logs/benchmark-claude_cli-20260215-144500.log
70
+ logs/generate-20260215-145001.log
71
+ ```
72
+
73
+ ## Logger hierarchy
74
+
75
+ ```
76
+ my_app ← root (FileHandler attached here)
77
+ ├── my_app.api ← get_logger("api", "my_app")
78
+ ├── my_app.nodes.text2spl ← get_logger("nodes.text2spl", "my_app")
79
+ └── my_app.flows ← get_logger("flows", "my_app")
80
+ ```
81
+
82
+ All child loggers inherit the root's handler — no per-module handler setup needed.
83
+
84
+ ## Design notes
85
+
86
+ - **`propagate=False`** — prevents duplicate output when a root Python logger
87
+ handler is already configured (e.g. Streamlit, pytest, Jupyter).
88
+ - **Stale-handler removal** — calling `setup_logging()` multiple times in one
89
+ process (e.g. test suites) is safe; old `FileHandler`s are replaced.
90
+ - **No third-party dependencies** — stdlib `logging` only.
91
+
92
+ ## Projects using dd-logging
93
+
94
+ | Project | Root name | Log dir |
95
+ |---------|-----------|---------|
96
+ | [spl-llm](https://github.com/digital-duck/SPL) | `spl` | `SPL/logs/` |
97
+ | [spl-flow](https://github.com/digital-duck/SPL-Flow) | `spl_flow` | `SPL-Flow/logs/` |
98
+
99
+ ## License
100
+
101
+ MIT
@@ -0,0 +1,18 @@
1
+ """dd-logging — shared logging helpers for Digital Duck projects."""
2
+ from dd_logging.core import (
3
+ FORMATTER,
4
+ LOG_LEVELS,
5
+ disable_logging,
6
+ get_logger,
7
+ setup_logging,
8
+ )
9
+
10
+ __version__ = "0.1.0"
11
+
12
+ __all__ = [
13
+ "setup_logging",
14
+ "get_logger",
15
+ "disable_logging",
16
+ "LOG_LEVELS",
17
+ "FORMATTER",
18
+ ]
@@ -0,0 +1,118 @@
1
+ """Core logging helpers shared across Digital Duck projects.
2
+
3
+ Provides a consistent, timestamped-file logging pattern for CLI tools and
4
+ Streamlit apps. Each project supplies its own *root_name* (the top-level
5
+ logger namespace) so hierarchies stay isolated:
6
+
7
+ spl → spl / spl.executor (spl-llm package)
8
+ spl_flow → spl_flow / spl_flow.nodes.* (spl-flow package)
9
+
10
+ Log file naming convention
11
+ --------------------------
12
+ <log_dir>/<run_name>[-<adapter>]-<YYYYMMDD-HHMMSS>.log
13
+ e.g. logs/run-openrouter-20260215-143022.log
14
+ logs/benchmark-claude_cli-20260215-144500.log
15
+ logs/generate-20260215-145001.log
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import logging
20
+ from datetime import datetime
21
+ from pathlib import Path
22
+
23
+ # ── Constants ──────────────────────────────────────────────────────────────────
24
+
25
+ LOG_LEVELS: dict[str, int] = {
26
+ "debug": logging.DEBUG,
27
+ "info": logging.INFO,
28
+ "warning": logging.WARNING,
29
+ "error": logging.ERROR,
30
+ }
31
+
32
+ FORMATTER = logging.Formatter(
33
+ "%(asctime)s %(levelname)-7s %(name)s %(message)s",
34
+ datefmt="%H:%M:%S",
35
+ )
36
+
37
+ # ── Public API ─────────────────────────────────────────────────────────────────
38
+
39
+ def setup_logging(
40
+ run_name: str,
41
+ *,
42
+ root_name: str,
43
+ adapter: str = "",
44
+ log_level: str = "info",
45
+ log_dir: Path | str | None = None,
46
+ console: bool = False,
47
+ ) -> Path:
48
+ """Attach a timestamped FileHandler to *root_name* logger.
49
+
50
+ Safe to call multiple times in one process — stale FileHandlers from
51
+ a previous call are removed before the new one is attached.
52
+
53
+ Parameters
54
+ ----------
55
+ run_name : short label for the filename, e.g. ``"run"``, ``"benchmark"``
56
+ root_name : root logger namespace, e.g. ``"spl"`` or ``"spl_flow"``
57
+ adapter : LLM adapter name appended to the filename (omitted if empty)
58
+ log_level : ``"debug"`` | ``"info"`` | ``"warning"`` | ``"error"``
59
+ log_dir : directory for log files; defaults to ``./logs`` relative to CWD
60
+ console : also attach a StreamHandler (useful in CLI --verbose mode)
61
+
62
+ Returns
63
+ -------
64
+ Path absolute path of the log file created
65
+ """
66
+ target_dir = Path(log_dir) if log_dir else Path.cwd() / "logs"
67
+ target_dir.mkdir(parents=True, exist_ok=True)
68
+
69
+ dt_str = datetime.now().strftime("%Y%m%d-%H%M%S")
70
+ suffix = f"-{adapter}" if adapter else ""
71
+ log_path = target_dir / f"{run_name}{suffix}-{dt_str}.log"
72
+
73
+ level = LOG_LEVELS.get(log_level.lower(), logging.INFO)
74
+
75
+ root = logging.getLogger(root_name)
76
+ root.setLevel(logging.DEBUG) # capture everything; handlers filter
77
+
78
+ # Remove stale FileHandlers from a previous setup_logging() call
79
+ root.handlers = [h for h in root.handlers if not isinstance(h, logging.FileHandler)]
80
+
81
+ fh = logging.FileHandler(log_path, encoding="utf-8")
82
+ fh.setLevel(level)
83
+ fh.setFormatter(FORMATTER)
84
+ root.addHandler(fh)
85
+
86
+ if console:
87
+ ch = logging.StreamHandler()
88
+ ch.setLevel(level)
89
+ ch.setFormatter(FORMATTER)
90
+ root.addHandler(ch)
91
+
92
+ # Prevent propagation to the Python root logger — avoids duplicate output
93
+ # in environments that configure their own root handler (e.g. Streamlit).
94
+ root.propagate = False
95
+
96
+ return log_path
97
+
98
+
99
+ def get_logger(name: str, root_name: str) -> logging.Logger:
100
+ """Return a child logger under *root_name*.
101
+
102
+ Parameters
103
+ ----------
104
+ name : dotted sub-path, e.g. ``"nodes.text2spl"`` or ``"executor"``
105
+ root_name : root logger namespace, e.g. ``"spl"`` or ``"spl_flow"``
106
+
107
+ Returns
108
+ -------
109
+ logging.Logger named ``<root_name>.<name>``
110
+ """
111
+ return logging.getLogger(f"{root_name}.{name}")
112
+
113
+
114
+ def disable_logging(root_name: str) -> None:
115
+ """Remove all handlers from *root_name* logger (no-op log mode)."""
116
+ root = logging.getLogger(root_name)
117
+ root.handlers.clear()
118
+ root.propagate = False
@@ -0,0 +1,123 @@
1
+ Metadata-Version: 2.4
2
+ Name: dd-logging
3
+ Version: 0.1.0
4
+ Summary: Shared logging helpers for Digital Duck projects (spl-llm, spl-flow, …)
5
+ Author-email: Wen Gong <wen.gong.research@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/digital-duck/dd-logging
8
+ Project-URL: Repository, https://github.com/digital-duck/dd-logging
9
+ Project-URL: Issues, https://github.com/digital-duck/dd-logging/issues
10
+ Keywords: logging,digital-duck,spl
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: System :: Logging
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Dynamic: license-file
22
+
23
+ # dd-logging
24
+
25
+ Shared logging helpers for [Digital Duck](https://github.com/digital-duck) projects.
26
+
27
+ Provides a consistent, timestamped-file logging pattern for CLI tools and Streamlit apps.
28
+ Used by **spl-llm** and **spl-flow**; designed to be reused by any project in the ecosystem.
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ # from PyPI (once published)
34
+ pip install dd-logging
35
+
36
+ # local editable install (for development)
37
+ pip install -e /path/to/dd-logging
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ ```python
43
+ from dd_logging import setup_logging, get_logger, disable_logging
44
+
45
+ # 1. Call once per process (CLI entry point or app startup)
46
+ log_path = setup_logging(
47
+ "run",
48
+ root_name="my_app", # top-level logger namespace
49
+ adapter="openrouter", # appended to filename (optional)
50
+ log_level="info", # debug | info | warning | error
51
+ )
52
+ # → logs/run-openrouter-20260215-143022.log
53
+
54
+ # 2. In each module
55
+ _log = get_logger("nodes.text2spl", root_name="my_app")
56
+ _log.info("translating query len=%d", len(query))
57
+
58
+ # 3. Silence all logging (e.g. --no-log CLI flag)
59
+ disable_logging("my_app")
60
+ ```
61
+
62
+ ### Thin wrapper pattern (recommended)
63
+
64
+ Each project wraps `dd_logging` so call-sites never pass `root_name`:
65
+
66
+ ```python
67
+ # myapp/logging_config.py
68
+ from pathlib import Path
69
+ from dd_logging import setup_logging as _setup, get_logger as _get, disable_logging as _disable
70
+
71
+ _ROOT = "my_app"
72
+ LOG_DIR = Path(__file__).resolve().parent.parent / "logs"
73
+
74
+ def get_logger(name: str):
75
+ return _get(name, _ROOT)
76
+
77
+ def setup_logging(run_name: str, **kw):
78
+ kw.setdefault("log_dir", LOG_DIR)
79
+ return _setup(run_name, root_name=_ROOT, **kw)
80
+
81
+ def disable_logging():
82
+ return _disable(_ROOT)
83
+ ```
84
+
85
+ ## Log file naming
86
+
87
+ ```
88
+ <log_dir>/<run_name>[-<adapter>]-<YYYYMMDD-HHMMSS>.log
89
+
90
+ logs/run-openrouter-20260215-143022.log
91
+ logs/benchmark-claude_cli-20260215-144500.log
92
+ logs/generate-20260215-145001.log
93
+ ```
94
+
95
+ ## Logger hierarchy
96
+
97
+ ```
98
+ my_app ← root (FileHandler attached here)
99
+ ├── my_app.api ← get_logger("api", "my_app")
100
+ ├── my_app.nodes.text2spl ← get_logger("nodes.text2spl", "my_app")
101
+ └── my_app.flows ← get_logger("flows", "my_app")
102
+ ```
103
+
104
+ All child loggers inherit the root's handler — no per-module handler setup needed.
105
+
106
+ ## Design notes
107
+
108
+ - **`propagate=False`** — prevents duplicate output when a root Python logger
109
+ handler is already configured (e.g. Streamlit, pytest, Jupyter).
110
+ - **Stale-handler removal** — calling `setup_logging()` multiple times in one
111
+ process (e.g. test suites) is safe; old `FileHandler`s are replaced.
112
+ - **No third-party dependencies** — stdlib `logging` only.
113
+
114
+ ## Projects using dd-logging
115
+
116
+ | Project | Root name | Log dir |
117
+ |---------|-----------|---------|
118
+ | [spl-llm](https://github.com/digital-duck/SPL) | `spl` | `SPL/logs/` |
119
+ | [spl-flow](https://github.com/digital-duck/SPL-Flow) | `spl_flow` | `SPL-Flow/logs/` |
120
+
121
+ ## License
122
+
123
+ MIT
@@ -0,0 +1,9 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ dd_logging/__init__.py
5
+ dd_logging/core.py
6
+ dd_logging.egg-info/PKG-INFO
7
+ dd_logging.egg-info/SOURCES.txt
8
+ dd_logging.egg-info/dependency_links.txt
9
+ dd_logging.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ dd_logging
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dd-logging"
7
+ version = "0.1.0"
8
+ description = "Shared logging helpers for Digital Duck projects (spl-llm, spl-flow, …)"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ {name = "Wen Gong", email = "wen.gong.research@gmail.com"},
14
+ ]
15
+ keywords = ["logging", "digital-duck", "spl"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: System :: Logging",
24
+ ]
25
+
26
+ [project.urls]
27
+ Homepage = "https://github.com/digital-duck/dd-logging"
28
+ Repository = "https://github.com/digital-duck/dd-logging"
29
+ Issues = "https://github.com/digital-duck/dd-logging/issues"
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["."]
33
+ include = ["dd_logging*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+