kstlib 3.2.0__tar.gz → 3.3.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.
- {kstlib-3.2.0/src/kstlib.egg-info → kstlib-3.3.0}/PKG-INFO +1 -1
- kstlib-3.3.0/src/kstlib/_shared/logging_helpers.py +40 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cache/strategies.py +4 -10
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/rapi/call.py +52 -14
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/config/sops.py +3 -13
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/db/database.py +2 -8
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/kstlib.conf.yml +4 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/logging/manager.py +11 -2
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/meta.py +1 -1
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/rapi/client.py +59 -57
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/rapi/config.py +14 -16
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/transform/chain.py +5 -9
- {kstlib-3.2.0 → kstlib-3.3.0/src/kstlib.egg-info}/PKG-INFO +1 -1
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib.egg-info/SOURCES.txt +1 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/LICENSE.md +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/MANIFEST.in +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/README.md +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/pyproject.toml +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/setup.cfg +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/__main__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/_shared/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/_shared/jinja.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/_shared/redaction.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/alerts/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/alerts/channels/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/alerts/channels/base.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/alerts/channels/email.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/alerts/channels/slack.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/alerts/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/alerts/manager.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/alerts/models.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/alerts/throttle.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/callback.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/check.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/config.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/errors.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/models.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/providers/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/providers/base.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/providers/oauth2.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/providers/oidc.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/session.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/auth/token.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cache/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cache/decorator.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/app.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/auth/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/auth/check.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/auth/common.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/auth/login.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/auth/logout.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/auth/providers.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/auth/status.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/auth/token.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/auth/whoami.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/config.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/ops/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/ops/attach.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/ops/common.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/ops/list_sessions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/ops/logs.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/ops/start.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/ops/status.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/ops/stop.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/rapi/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/rapi/list.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/rapi/show.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/secrets/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/secrets/common.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/secrets/decrypt.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/secrets/doctor.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/secrets/encrypt.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/commands/secrets/shred.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/cli/common.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/config/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/config/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/config/export.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/config/loader.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/db/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/db/aiosqlcipher.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/db/cipher.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/db/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/db/pool.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/helpers/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/helpers/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/helpers/time_trigger.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/limits.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/logging/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/_helpers.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/builder.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/collector.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/filesystem.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/throttle.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/transport.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/transports/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/transports/gmail.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/transports/resend.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/transports/ses.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/mail/transports/smtp.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/metrics/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/metrics/decorators.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/metrics/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/_styles.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/cell.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/config.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/delivery.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/image.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/kv.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/list.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/metric.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/monitoring.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/renderer.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/service.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/table.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/monitoring/types.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ops/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ops/base.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ops/container.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ops/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ops/manager.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ops/models.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ops/tmux.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ops/validators.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/base.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/models.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/runner.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/steps/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/steps/_base.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/steps/_helpers.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/steps/callable.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/steps/python.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/steps/shell.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/pipeline/validators.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/py.typed +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/rapi/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/rapi/credentials.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/rapi/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/resilience/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/resilience/circuit_breaker.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/resilience/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/resilience/heartbeat.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/resilience/rate_limiter.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/resilience/shutdown.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/resilience/watchdog.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/models.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/providers/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/providers/base.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/providers/environment.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/providers/keyring.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/providers/kms.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/providers/kwargs.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/providers/sops.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/resolver.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secrets/sensitive.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secure/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secure/fs.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secure/passwords.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/secure/permissions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ssl.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/transform/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/transform/config.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/transform/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/transform/primitives.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/transform/validators.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ui/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ui/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ui/panels.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ui/spinner.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/ui/tables.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/utils/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/utils/dict.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/utils/formatting.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/utils/http_trace.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/utils/lazy.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/utils/secure_delete.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/utils/serialization.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/utils/text.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/utils/validators.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/websocket/__init__.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/websocket/exceptions.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/websocket/manager.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib/websocket/models.py +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib.egg-info/dependency_links.txt +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib.egg-info/entry_points.txt +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib.egg-info/requires.txt +0 -0
- {kstlib-3.2.0 → kstlib-3.3.0}/src/kstlib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kstlib
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: Config-driven helpers for Python projects (dynamic config, secure secrets, preset logging, and more…)
|
|
5
5
|
Author-email: Michel TRUONG <michel.truong@gmail.com>
|
|
6
6
|
Maintainer-email: Michel TRUONG <michel.truong@gmail.com>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Shared TRACE-level logging helper (private to kstlib internals).
|
|
2
|
+
|
|
3
|
+
Consolidates the ``_log_trace`` helper that was previously duplicated across
|
|
4
|
+
several sub-packages into a single shared emitter. Modules pass their own
|
|
5
|
+
logger so emission stays attributed to the calling module's name.
|
|
6
|
+
|
|
7
|
+
This module must never import ``kstlib.logging`` at top level: see
|
|
8
|
+
:func:`log_trace` for the circular-import rationale.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
import logging
|
|
17
|
+
|
|
18
|
+
__all__ = ["log_trace"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def log_trace(logger: logging.Logger, msg: str, *args: object) -> None:
|
|
22
|
+
"""Emit a TRACE-level (custom level 5) record on the given logger.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
logger: Target standard-library logger to emit the record on.
|
|
26
|
+
msg: Log message, optionally containing ``%``-style placeholders.
|
|
27
|
+
*args: Positional arguments interpolated into ``msg`` lazily by the
|
|
28
|
+
logging framework (only when the record is actually emitted).
|
|
29
|
+
|
|
30
|
+
Note:
|
|
31
|
+
``TRACE_LEVEL`` is imported lazily inside the function to avoid the
|
|
32
|
+
circular import chain
|
|
33
|
+
``kstlib.logging.manager -> kstlib.config -> kstlib.config.sops``.
|
|
34
|
+
Importing ``kstlib.logging`` at module top level would resurrect that
|
|
35
|
+
cycle as soon as a cascade module (e.g. ``kstlib.config.sops``) imports
|
|
36
|
+
this helper.
|
|
37
|
+
"""
|
|
38
|
+
from kstlib.logging import TRACE_LEVEL
|
|
39
|
+
|
|
40
|
+
logger.log(TRACE_LEVEL, msg, *args)
|
|
@@ -29,19 +29,13 @@ from collections.abc import Callable
|
|
|
29
29
|
from pathlib import Path
|
|
30
30
|
from typing import Any, TypeVar, cast
|
|
31
31
|
|
|
32
|
+
from kstlib._shared.logging_helpers import log_trace
|
|
32
33
|
from kstlib.limits import CacheLimits, get_cache_limits
|
|
33
34
|
from kstlib.utils.formatting import format_bytes
|
|
34
35
|
|
|
35
36
|
logger = logging.getLogger(__name__)
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
def _log_trace(msg: str, *args: object) -> None:
|
|
39
|
-
"""Log at TRACE level (custom level 5, below DEBUG)."""
|
|
40
|
-
from kstlib.logging import TRACE_LEVEL
|
|
41
|
-
|
|
42
|
-
logger.log(TRACE_LEVEL, msg, *args)
|
|
43
|
-
|
|
44
|
-
|
|
45
39
|
_CACHE_FORMAT_VERSION = "kstlib:file-cache:v1"
|
|
46
40
|
_SUPPORTED_SERIALIZERS: set[str] = {"json", "pickle", "auto"}
|
|
47
41
|
_PICKLE_SAFE_BUILTINS: set[str] = {
|
|
@@ -190,7 +184,7 @@ class TTLCacheStrategy(CacheStrategy):
|
|
|
190
184
|
if key not in self._cache:
|
|
191
185
|
# The key is the SHA256 hash from make_key; logging it is safe
|
|
192
186
|
# by construction (never the function args themselves).
|
|
193
|
-
|
|
187
|
+
log_trace(logger, "[CACHE] TTL miss: key=%s", key)
|
|
194
188
|
return None
|
|
195
189
|
|
|
196
190
|
value, expiry = self._cache[key]
|
|
@@ -198,10 +192,10 @@ class TTLCacheStrategy(CacheStrategy):
|
|
|
198
192
|
# Check expiration
|
|
199
193
|
if time.time() > expiry:
|
|
200
194
|
del self._cache[key]
|
|
201
|
-
|
|
195
|
+
log_trace(logger, "[CACHE] TTL miss (expired): key=%s", key)
|
|
202
196
|
return None
|
|
203
197
|
|
|
204
|
-
|
|
198
|
+
log_trace(logger, "[CACHE] TTL hit: key=%s", key)
|
|
205
199
|
return value
|
|
206
200
|
|
|
207
201
|
def set(self, key: str, value: Any) -> None:
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
+
import re
|
|
6
7
|
from typing import TYPE_CHECKING, Annotated, Any, cast
|
|
7
8
|
|
|
8
9
|
import typer
|
|
@@ -530,19 +531,44 @@ def _emit_extracted_value(
|
|
|
530
531
|
print(content)
|
|
531
532
|
|
|
532
533
|
|
|
533
|
-
def
|
|
534
|
+
def _split_extracted_keys(spec: str) -> list[str]:
|
|
535
|
+
"""Split a ``--show-extracted`` spec on commas/whitespace, dropping empties.
|
|
536
|
+
|
|
537
|
+
Examples:
|
|
538
|
+
>>> _split_extracted_keys("v1,v2")
|
|
539
|
+
['v1', 'v2']
|
|
540
|
+
>>> _split_extracted_keys("v1 v2")
|
|
541
|
+
['v1', 'v2']
|
|
542
|
+
>>> _split_extracted_keys("v1, ,v2")
|
|
543
|
+
['v1', 'v2']
|
|
544
|
+
>>> _split_extracted_keys("")
|
|
545
|
+
[]
|
|
546
|
+
|
|
547
|
+
"""
|
|
548
|
+
return [key for key in re.split(r"[,\s]+", spec) if key]
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
def _resolve_show_extracted(response: RapiResponse, spec: str) -> tuple[Any, str | None]:
|
|
534
552
|
"""Resolve the ``--show-extracted`` value and its empty-policy hint.
|
|
535
553
|
|
|
536
|
-
The
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
554
|
+
The failure semantics follow the output form:
|
|
555
|
+
|
|
556
|
+
- No ``spec`` (bare flag): the whole ``extracted`` mapping is returned as a
|
|
557
|
+
dict (exit 0; a missing ``extract:`` directive still fails).
|
|
558
|
+
- A single key: the raw value is returned and a None value fails (exit 1),
|
|
559
|
+
mirroring ``--pick``. This keeps backward compatibility with v3.2.0
|
|
560
|
+
scripts that read one key.
|
|
561
|
+
- Several keys (comma/space-separated): a JSON object subset is returned
|
|
562
|
+
(exit 0). A declared key whose expression matched nothing appears as
|
|
563
|
+
``null``; only an unknown key fails.
|
|
564
|
+
|
|
565
|
+
An endpoint without an ``extract:`` directive, or an unknown key, is a
|
|
566
|
+
usage failure (exit 1 via the hint). Hints name keys only, never values.
|
|
542
567
|
|
|
543
568
|
Args:
|
|
544
569
|
response: The API response whose ``extracted`` mapping is read.
|
|
545
|
-
|
|
570
|
+
spec: The requested keys (comma/space-separated), or an empty string
|
|
571
|
+
to select all keys.
|
|
546
572
|
|
|
547
573
|
Returns:
|
|
548
574
|
Tuple of (value to emit, empty hint). The hint is consumed by
|
|
@@ -552,12 +578,22 @@ def _resolve_show_extracted(response: RapiResponse, key: str) -> tuple[Any, str
|
|
|
552
578
|
extracted: Mapping[str, Any] = response.extracted
|
|
553
579
|
if not extracted:
|
|
554
580
|
return None, "No extract: directive declared for this endpoint."
|
|
555
|
-
|
|
581
|
+
keys = _split_extracted_keys(spec)
|
|
582
|
+
if not keys:
|
|
556
583
|
return dict(extracted), None
|
|
557
|
-
if
|
|
584
|
+
if len(keys) == 1:
|
|
585
|
+
key = keys[0]
|
|
586
|
+
if key not in extracted:
|
|
587
|
+
available = ", ".join(sorted(extracted))
|
|
588
|
+
return None, f"No extracted key '{key}'. Available: {available}."
|
|
589
|
+
return extracted.get(key), f"Extracted key '{key}' matched nothing."
|
|
590
|
+
missing = [key for key in keys if key not in extracted]
|
|
591
|
+
if missing:
|
|
558
592
|
available = ", ".join(sorted(extracted))
|
|
559
|
-
|
|
560
|
-
|
|
593
|
+
noun = "key" if len(missing) == 1 else "keys"
|
|
594
|
+
names = ", ".join(f"'{key}'" for key in missing)
|
|
595
|
+
return None, f"No extracted {noun} {names}. Available: {available}."
|
|
596
|
+
return {key: extracted[key] for key in keys}, None
|
|
561
597
|
|
|
562
598
|
|
|
563
599
|
def _handle_extraction_output(
|
|
@@ -811,10 +847,12 @@ def call(
|
|
|
811
847
|
str | None,
|
|
812
848
|
typer.Option(
|
|
813
849
|
"--show-extracted",
|
|
814
|
-
metavar="[KEY]",
|
|
850
|
+
metavar="[KEY[,KEY...]]",
|
|
815
851
|
help=(
|
|
816
852
|
"Print values declared by the endpoint extract: directive. "
|
|
817
|
-
"
|
|
853
|
+
"One KEY prints that value; several comma/space-separated keys "
|
|
854
|
+
"print a JSON object subset; without a value, print all keys as JSON. "
|
|
855
|
+
'Quote keys with spaces ("v1 v2") or join with commas (v1,v2) so the shell does not split them.'
|
|
818
856
|
),
|
|
819
857
|
),
|
|
820
858
|
] = None,
|
|
@@ -28,6 +28,7 @@ import subprocess
|
|
|
28
28
|
from collections import OrderedDict
|
|
29
29
|
from typing import Any
|
|
30
30
|
|
|
31
|
+
from kstlib._shared.logging_helpers import log_trace
|
|
31
32
|
from kstlib.config.exceptions import ConfigSopsError, ConfigSopsNotAvailableError
|
|
32
33
|
from kstlib.limits import (
|
|
33
34
|
DEFAULT_MAX_SOPS_CACHE_ENTRIES,
|
|
@@ -37,17 +38,6 @@ from kstlib.limits import (
|
|
|
37
38
|
logger = logging.getLogger(__name__)
|
|
38
39
|
|
|
39
40
|
|
|
40
|
-
def _log_trace(msg: str, *args: object) -> None:
|
|
41
|
-
"""Log at TRACE level (custom level 5, below DEBUG).
|
|
42
|
-
|
|
43
|
-
Uses a lazy import to avoid the circular import chain
|
|
44
|
-
``kstlib.logging.manager -> kstlib.config -> kstlib.config.sops``.
|
|
45
|
-
"""
|
|
46
|
-
from kstlib.logging import TRACE_LEVEL
|
|
47
|
-
|
|
48
|
-
logger.log(TRACE_LEVEL, msg, *args)
|
|
49
|
-
|
|
50
|
-
|
|
51
41
|
SOPS_FILE_PATTERNS: tuple[str, ...] = (
|
|
52
42
|
".sops.yml",
|
|
53
43
|
".sops.yaml",
|
|
@@ -217,7 +207,7 @@ class SopsDecryptor:
|
|
|
217
207
|
cached = self._cache.get(resolved)
|
|
218
208
|
if cached and cached[0] == mtime:
|
|
219
209
|
self._cache.move_to_end(resolved)
|
|
220
|
-
|
|
210
|
+
log_trace(logger, "SOPS cache hit for: %s", path.name)
|
|
221
211
|
return cached[1]
|
|
222
212
|
|
|
223
213
|
# Security: reject absolute/relative paths to prevent binary override via config
|
|
@@ -269,7 +259,7 @@ class SopsDecryptor:
|
|
|
269
259
|
else:
|
|
270
260
|
removed = self._cache.pop(path.resolve(), None)
|
|
271
261
|
if removed:
|
|
272
|
-
|
|
262
|
+
log_trace(logger, "SOPS cache entry removed: %s", path.name)
|
|
273
263
|
|
|
274
264
|
@property
|
|
275
265
|
def cache_size(self) -> int:
|
|
@@ -17,6 +17,7 @@ from typing import TYPE_CHECKING, Any, cast
|
|
|
17
17
|
|
|
18
18
|
from typing_extensions import Self
|
|
19
19
|
|
|
20
|
+
from kstlib._shared.logging_helpers import log_trace
|
|
20
21
|
from kstlib.db.exceptions import TransactionError
|
|
21
22
|
from kstlib.db.pool import ConnectionPool, PoolStats
|
|
22
23
|
|
|
@@ -35,13 +36,6 @@ log = logging.getLogger(__name__)
|
|
|
35
36
|
_SQL_TRACE_TRUNCATE = 200
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
def _log_trace(msg: str, *args: object) -> None:
|
|
39
|
-
"""Log at TRACE level (custom level 5, below DEBUG)."""
|
|
40
|
-
from kstlib.logging import TRACE_LEVEL
|
|
41
|
-
|
|
42
|
-
log.log(TRACE_LEVEL, msg, *args)
|
|
43
|
-
|
|
44
|
-
|
|
45
39
|
def _truncate_sql(sql: str, limit: int = _SQL_TRACE_TRUNCATE) -> str:
|
|
46
40
|
"""Return ``sql`` truncated to ``limit`` characters, single-line."""
|
|
47
41
|
flat = " ".join(sql.split())
|
|
@@ -254,7 +248,7 @@ class AsyncDatabase:
|
|
|
254
248
|
# Sanitization invariant : log the truncated SQL only, NEVER the
|
|
255
249
|
# parameters tuple (would leak PII / credentials in WHERE/INSERT
|
|
256
250
|
# values). Truncation prevents giant DDL from drowning the trace.
|
|
257
|
-
|
|
251
|
+
log_trace(log, "[DB] Execute: %s (params=%s)", _truncate_sql(sql), "yes" if parameters else "no")
|
|
258
252
|
pool = self._ensure_pool()
|
|
259
253
|
async with pool.connection() as conn:
|
|
260
254
|
if parameters:
|
|
@@ -175,6 +175,10 @@ logger:
|
|
|
175
175
|
format: "::: PID %(process)d / TID %(thread)d ::: %(message)s"
|
|
176
176
|
show_path: true
|
|
177
177
|
tracebacks_show_locals: true
|
|
178
|
+
# Console routing: stdout (default) | stderr. Route to stderr when the CLI
|
|
179
|
+
# emits data/JSON on stdout, so logs do not corrupt the piped output
|
|
180
|
+
# (Unix data vs diagnostics separation). Invalid values raise ConfigError.
|
|
181
|
+
stream: stdout
|
|
178
182
|
|
|
179
183
|
# File handler settings
|
|
180
184
|
# Two configuration styles are supported:
|
|
@@ -49,7 +49,7 @@ from rich.logging import RichHandler
|
|
|
49
49
|
from rich.theme import Theme
|
|
50
50
|
from rich.traceback import Traceback
|
|
51
51
|
|
|
52
|
-
from kstlib.config import get_config
|
|
52
|
+
from kstlib.config import ConfigError, get_config
|
|
53
53
|
|
|
54
54
|
# =============================================================================
|
|
55
55
|
# HARDCODED LIMITS (Deep Defense)
|
|
@@ -253,6 +253,7 @@ FALLBACK_DEFAULTS = {
|
|
|
253
253
|
"format": "::: PID %(process)d / TID %(thread)d ::: %(message)s",
|
|
254
254
|
"show_path": True,
|
|
255
255
|
"tracebacks_show_locals": False,
|
|
256
|
+
"stream": "stdout",
|
|
256
257
|
},
|
|
257
258
|
"file": {
|
|
258
259
|
"level": "DEBUG",
|
|
@@ -340,7 +341,15 @@ class LogManager(logging.Logger):
|
|
|
340
341
|
# Setup console and theme
|
|
341
342
|
self.width = shutil.get_terminal_size(fallback=(120, 30)).columns
|
|
342
343
|
theme = self._create_theme()
|
|
343
|
-
|
|
344
|
+
# Route console output to stdout (default) or stderr. Routing to stderr
|
|
345
|
+
# keeps stdout clean for CLIs that emit data/JSON there (Unix data vs
|
|
346
|
+
# diagnostics separation). Fail fast on a typo so a misconfigured value
|
|
347
|
+
# never silently falls back to stdout and corrupts piped data.
|
|
348
|
+
stream = self._config.console.get("stream", "stdout")
|
|
349
|
+
if stream not in ("stdout", "stderr"):
|
|
350
|
+
raise ConfigError(f"Invalid console.stream {stream!r}: expected 'stdout' or 'stderr'")
|
|
351
|
+
_internal_log.debug("[INIT] console stream resolved to %r", stream)
|
|
352
|
+
self.console = Console(theme=theme, width=self.width, stderr=(stream == "stderr"))
|
|
344
353
|
|
|
345
354
|
# Setup handlers
|
|
346
355
|
self._setup_handlers()
|