Skip to content

Commit 441354f

Browse files
committed
5.7.3 - Allow disabling log forwarding
1 parent 92223c2 commit 441354f

File tree

9 files changed

+46
-73
lines changed

9 files changed

+46
-73
lines changed

.github/workflows/python-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ jobs:
7777
7878
- run: |
7979
mk python-release owner=vkottler \
80-
repo=runtimepy version=5.7.2
80+
repo=runtimepy version=5.7.3
8181
if: |
8282
matrix.python-version == '3.12'
8383
&& matrix.system == 'ubuntu-latest'

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
=====================================
33
generator=datazen
44
version=3.1.4
5-
hash=618546df79dd7f387faa6f84f9a58c79
5+
hash=ef917873929a5dc6a70367fde7f1447f
66
=====================================
77
-->
88

9-
# runtimepy ([5.7.2](https://pypi.org/project/runtimepy/))
9+
# runtimepy ([5.7.3](https://pypi.org/project/runtimepy/))
1010

1111
[![python](https://img.shields.io/pypi/pyversions/runtimepy.svg)](https://pypi.org/project/runtimepy/)
1212
![Build Status](https://github.com/vkottler/runtimepy/workflows/Python%20Package/badge.svg)

local/variables/package.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
22
major: 5
33
minor: 7
4-
patch: 2
4+
patch: 3
55
entry: runtimepy

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta:__legacy__"
44

55
[project]
66
name = "runtimepy"
7-
version = "5.7.2"
7+
version = "5.7.3"
88
description = "A framework for implementing Python services."
99
readme = "README.md"
1010
requires-python = ">=3.11"

runtimepy/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# =====================================
22
# generator=datazen
33
# version=3.1.4
4-
# hash=0a0c607a8f78dc35cf48427539c9bafa
4+
# hash=37a32f51e0bf04276100ce27658b7f8f
55
# =====================================
66

77
"""
@@ -10,7 +10,7 @@
1010

1111
DESCRIPTION = "A framework for implementing Python services."
1212
PKG_NAME = "runtimepy"
13-
VERSION = "5.7.2"
13+
VERSION = "5.7.3"
1414

1515
# runtimepy-specific content.
1616
METRICS_NAME = "metrics"

runtimepy/mixins/logging.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
# third-party
1212
import aiofiles
13-
from vcorelib.logging import LoggerMixin, LoggerType
13+
from vcorelib.logging import ListLogger, LoggerMixin, LoggerType
1414
from vcorelib.paths import Pathlike, normalize
1515

1616
# internal
@@ -66,6 +66,25 @@ def setup_level_channel(
6666

6767

6868
LogPaths = Iterable[tuple[LogLevellike, Pathlike]]
69+
EXT_LOG_EXTRA = {"external": True}
70+
71+
72+
def handle_safe_log(
73+
logger: LoggerType, level: int, data: str, safe_to_log: bool
74+
) -> None:
75+
"""handle a log filtering scenario."""
76+
77+
if safe_to_log:
78+
logger.log(level, data, extra=EXT_LOG_EXTRA)
79+
else:
80+
record = logging.LogRecord(
81+
logger.name, level, __file__, -1, data, (), None
82+
)
83+
record.external = True
84+
85+
for handler in logger.handlers: # type: ignore
86+
if isinstance(handler, ListLogger):
87+
handler.emit(record)
6988

7089

7190
class LogCaptureMixin:
@@ -76,7 +95,10 @@ class LogCaptureMixin:
7695
# Open aiofiles handles.
7796
streams: list[tuple[int, Any]]
7897

79-
ext_log_extra = {"external": True}
98+
# Set false to only forward to ListLogger handlers. Required for when the
99+
# system log / process-management logs are being forwarded (otherwise also
100+
# logging would lead to infinite spam).
101+
safe_to_log = True
80102

81103
async def init_log_capture(
82104
self, stack: AsyncExitStack, log_paths: LogPaths
@@ -98,7 +120,8 @@ async def init_log_capture(
98120

99121
def log_line(self, level: int, data: str) -> None:
100122
"""Log a line for output."""
101-
self.logger.log(level, data, extra=self.ext_log_extra)
123+
124+
handle_safe_log(self.logger, level, data, self.safe_to_log)
102125

103126
async def dispatch_log_capture(self) -> None:
104127
"""Get the next line from this log stream."""

tasks/dev.yaml

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,6 @@ includes:
44
- dev_no_wait.yaml
55
- ../tests/data/valid/connection_arbiter/test_ssl.yaml
66

7-
factories:
8-
- {name: tasks.tlm.LogCapture}
9-
tasks:
10-
- name: root_log
11-
factory: log_capture
12-
period_s: 0.1
13-
markdown: |
14-
*something isn't looking right...*
15-
16-
**why's it looking like that...**
17-
18-
***why's it looking like THAT...***
19-
20-
`nice mono stuff there`
21-
22-
*`nice slanted mono yeah`*
23-
24-
**`nice mono bold type shit there`**
25-
26-
***`nice mono bold type slant shit there`***
27-
28-
ligature type shit \_\_\_|\_\_\_ ligature type shit
29-
307
port_overrides:
318
runtimepy_https_server: 8443
329

tasks/tlm.py

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,9 @@
44

55
# built-in
66
import asyncio
7-
import os
8-
from pathlib import Path
97

108
# internal
11-
from runtimepy.mixins.logging import LogCaptureMixin
129
from runtimepy.net.arbiter import AppInfo
13-
from runtimepy.net.arbiter.task import ArbiterTask as _ArbiterTask
14-
from runtimepy.net.arbiter.task import TaskFactory as _TaskFactory
1510

1611

1712
async def sample_app(app: AppInfo) -> int:
@@ -24,36 +19,3 @@ async def sample_app(app: AppInfo) -> int:
2419
await asyncio.sleep(0.01)
2520

2621
return 0
27-
28-
29-
class LogCaptureTask(_ArbiterTask, LogCaptureMixin):
30-
"""
31-
A task that captures all log messages emitted by this program instance.
32-
"""
33-
34-
auto_finalize = True
35-
36-
async def init(self, app: AppInfo) -> None:
37-
"""Initialize this task with application information."""
38-
39-
await super().init(app)
40-
41-
# See above comment, we can probably keep the mixin class but delete
42-
# this one - unless we want a separate "Linux" task to run / handle
43-
# this (we might want to increase the housekeeping task rate to reduce
44-
# async command latency + connection processing?).
45-
await self.init_log_capture(
46-
app.stack, [("info", Path(os.sep, "var", "log", "syslog"))]
47-
)
48-
49-
async def dispatch(self) -> bool:
50-
"""Dispatch an iteration of this task."""
51-
52-
await self.dispatch_log_capture()
53-
return True
54-
55-
56-
class LogCapture(_TaskFactory[LogCaptureTask]):
57-
"""A factory for the syslog capture task."""
58-
59-
kind = LogCaptureTask

tests/mixins/test_logging.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,31 @@
44

55
# built-in
66
from contextlib import AsyncExitStack
7+
import logging
78

89
# third-party
910
from pytest import mark
10-
from vcorelib.logging import LoggerMixin
11+
from vcorelib.logging import ListLogger, LoggerMixin
1112
from vcorelib.paths.context import tempfile
1213

1314
# module under test
14-
from runtimepy.mixins.logging import LogCaptureMixin
15+
from runtimepy.mixins.logging import LogCaptureMixin, handle_safe_log
1516

1617

1718
class SampleLogger(LoggerMixin, LogCaptureMixin):
1819
"""A sample class."""
1920

2021

22+
def test_handle_safe_log_basic():
23+
"""Test basic scenarios for the 'handle_safe_log' method."""
24+
25+
logger = logging.getLogger(__name__)
26+
logger.addHandler(ListLogger.create())
27+
28+
handle_safe_log(logger, logging.INFO, "message", True)
29+
handle_safe_log(logger, logging.INFO, "message", False)
30+
31+
2132
@mark.asyncio
2233
async def test_log_capture_mixin_basic():
2334
"""Test basic interactions with a log capture."""

0 commit comments

Comments
 (0)