We've been running @terchris/sovdev-logger@1.0.2 in production for a few
weeks (a TypeScript/Node 22 API, esbuild-bundled to a single .mjs file,
deployed on Cloud Run) and collected a batch of findings along the way.
Grouped by category, strongest first.
Bugs
1. sovdev_generate_trace_id is documented but not exported in 1.0.2.
The README's "Common Logging Patterns" section ("Using traceId to Link
Operations") documents this function, but it isn't in the published
package:
$ node -e "console.log(Object.keys(await import('@terchris/sovdev-logger')))"
# 13 exports listed — sovdev_generate_trace_id is not among them
$ tsc --noEmit
# Module '"@terchris/sovdev-logger"' has no exported member 'sovdev_generate_trace_id'
So the README's whole "link a multi-step operation under one traceId"
pattern is currently unusable as written. We worked around it with
sovdev_start_span/sovdev_end_span (which do exist and work, and give
real span duration on top of trace correlation) — but a documented public
API that silently doesn't exist will trip up anyone who follows the
README rather than the E2E example. Either ship the function or remove it
from the docs until it is.
2. sovdev_test_otlp_connection() treats HTTP 204 as a failure for the logs endpoint.
Against otlp-gateway-prod-eu-west-0.grafana.net, the helper returns:
{ "reachable": false, "error": "HTTP 204: No Content" }
204 is normally a healthy, empty-body response, not an error — and the
metrics/traces checks (same host, different paths) both reported
reachable: true. The actual sovdev_log() call afterward completed with
no flush error, so logs were very likely delivered — the connectivity
check's logs-endpoint branch appears to require a non-204 response when it
probably shouldn't.
Feature request: request-scoped context propagation
sovdev_log()'s signature requires every field explicit on every call
(level, function_name, message, peer_service, input_json?, response_json?, exception_object?) — there's no ambient/"request-scoped" way to set a
value once (e.g. per HTTP request) and have it inherit into every
sovdev_log call downstream without re-passing it. In a service with many
call sites, this means genuinely cross-cutting fields (a caller/application
identifier, an acting-user id) have to be manually threaded through every
function signature down to the log call.
A concrete ask: something like sovdev_set_context({...}), called once
per request/middleware, backed by AsyncLocalStorage (or OTel's own
context/baggage primitives, since the library already wraps the OTel
SDK — sovdev_start_span returns a real @opentelemetry/api Span, so
this machinery likely already exists inside the library). Every
sovdev_log() call downstream would read the ambient context and merge it
into the emitted log automatically.
This isn't a novel idea — it's the same shape as:
- OpenTelemetry's own
context API (Node's AsyncLocalStorageContextManager)
- Java/Logback's MDC, .NET's logger scopes (
AsyncLocal<T>), Python
structlog's contextvars — every mature logging ecosystem converged on
this independently
- W3C Baggage, if the value ever needs to survive a network hop between
services (not our immediate need, but worth the API being extensible
toward it)
We're not asking the library to decide what the field should be named or
how trustworthy it is (self-reported vs. verified) — just for a mechanism
to propagate whatever we choose without re-passing it at every call site.
Documentation gaps
LOG_TO_FILE isn't mentioned in the onboarding guide. Local file
logging (./logs/dev.log) is on by default, which has no value on
ephemeral/serverless filesystems (Cloud Run, Lambda, etc.). Setting
LOG_TO_FILE=false cleanly disables it, but we only found the env var by
reading source — worth a line in the onboarding guide recommending it for
containerized/serverless deployments.
- Auto-instrumentation's import-order requirement is only in a code
comment, not a warning. The E2E example dynamically import()s a
module inside a function specifically so OpenTelemetry's
auto-instrumentation can patch it before use — because ES module imports
are hoisted, a top-of-file import runs before sovdev_initialize() ever
could. The example's comment notes production apps should use a separate
instrumentation.js + node --require instead, but this isn't called
out as a warning anywhere prominent (onboarding guide, README
quick-start). A new integrator following the quick-start (not the E2E
example) could get silently-unpatched auto-instrumentation with no
warning at all.
- The ERROR/FATAL → ServiceNow-incident behavior isn't in the onboarding
guide. The README's "Compliance" section documents it clearly, but the
onboarding guide doesn't repeat the warning — worth a callout there too
("avoid ERROR/FATAL during initial integration testing — they may open
real incidents"), since onboarding is where a new integrator is most
likely to log a test ERROR before knowing this.
- Expected bundle size growth isn't documented. A minimal integration
(a few lines + the library) added ~7.5 MB to an esbuild --bundle
single-file output. Not disqualifying at typical serverless scale, but
worth a line in the onboarding guide so integrators aren't surprised.
Dependency versions — 4 Dependabot alerts (2 high, 2 moderate)
1.0.2's pinned OpenTelemetry dependencies are behind their patched
versions:
| Package |
Installed via ^ range |
Patched version |
@opentelemetry/sdk-node |
^0.55.0 |
0.217.0 |
@opentelemetry/auto-instrumentations-node |
^0.51.0 |
0.75.0 |
@opentelemetry/core (transitive) |
pinned 1.28.0/1.30.1 across the tree |
2.8.0 |
uuid (transitive, via gcp-metadata/gaxios) |
^9.0.1 |
11.1.1 |
We checked the real-world exposure for each and none have an exploitable
path in our own deployment (the high-severity ones require the Prometheus
pull-exporter to be enabled, which we don't use; the moderate ones require
either inbound W3C baggage header extraction or a direct uuid.v3/v5/v6
call with an external buffer, neither of which we do) — but that's
deployment-specific luck, not something the package should rely on
integrators to verify individually. The current ^0.51.0/^0.55.0 ranges
don't reach the patched versions, so this needs a version bump in a future
release rather than something we can resolve on our end.
A couple of things that worked well, for what it's worth
esbuild --bundle --platform=node --format=esm --target=node22 bundled
cleanly — ran identically bundled and unbundled against the real OTLP
endpoints, verified on the Grafana dashboard (both forms delivered real
telemetry). The feared auto-instrumentation-vs-single-file-bundle
conflict didn't materialize for a manual sovdev_log/span usage pattern.
- The
company-lookup.ts E2E example is a genuinely good teaching
artifact — more prescriptive than the quick-start alone (paired
start/success/error logs, job_status/job_progress for batch work,
trace correlation via spans). Worth pointing new integrators to it
directly.
Happy to share more detail on any of the above if useful.
We've been running
@terchris/sovdev-logger@1.0.2in production for a fewweeks (a TypeScript/Node 22 API,
esbuild-bundled to a single.mjsfile,deployed on Cloud Run) and collected a batch of findings along the way.
Grouped by category, strongest first.
Bugs
1.
sovdev_generate_trace_idis documented but not exported in1.0.2.The README's "Common Logging Patterns" section ("Using traceId to Link
Operations") documents this function, but it isn't in the published
package:
So the README's whole "link a multi-step operation under one traceId"
pattern is currently unusable as written. We worked around it with
sovdev_start_span/sovdev_end_span(which do exist and work, and givereal span duration on top of trace correlation) — but a documented public
API that silently doesn't exist will trip up anyone who follows the
README rather than the E2E example. Either ship the function or remove it
from the docs until it is.
2.
sovdev_test_otlp_connection()treats HTTP 204 as a failure for the logs endpoint.Against
otlp-gateway-prod-eu-west-0.grafana.net, the helper returns:{ "reachable": false, "error": "HTTP 204: No Content" }204 is normally a healthy, empty-body response, not an error — and the
metrics/traces checks (same host, different paths) both reported
reachable: true. The actualsovdev_log()call afterward completed withno flush error, so logs were very likely delivered — the connectivity
check's logs-endpoint branch appears to require a non-204 response when it
probably shouldn't.
Feature request: request-scoped context propagation
sovdev_log()'s signature requires every field explicit on every call(
level, function_name, message, peer_service, input_json?, response_json?, exception_object?) — there's no ambient/"request-scoped" way to set avalue once (e.g. per HTTP request) and have it inherit into every
sovdev_logcall downstream without re-passing it. In a service with manycall sites, this means genuinely cross-cutting fields (a caller/application
identifier, an acting-user id) have to be manually threaded through every
function signature down to the log call.
A concrete ask: something like
sovdev_set_context({...}), called onceper request/middleware, backed by
AsyncLocalStorage(or OTel's owncontext/baggageprimitives, since the library already wraps the OTelSDK —
sovdev_start_spanreturns a real@opentelemetry/apiSpan, sothis machinery likely already exists inside the library). Every
sovdev_log()call downstream would read the ambient context and merge itinto the emitted log automatically.
This isn't a novel idea — it's the same shape as:
contextAPI (Node'sAsyncLocalStorageContextManager)AsyncLocal<T>), Pythonstructlog'scontextvars— every mature logging ecosystem converged onthis independently
services (not our immediate need, but worth the API being extensible
toward it)
We're not asking the library to decide what the field should be named or
how trustworthy it is (self-reported vs. verified) — just for a mechanism
to propagate whatever we choose without re-passing it at every call site.
Documentation gaps
LOG_TO_FILEisn't mentioned in the onboarding guide. Local filelogging (
./logs/dev.log) is on by default, which has no value onephemeral/serverless filesystems (Cloud Run, Lambda, etc.). Setting
LOG_TO_FILE=falsecleanly disables it, but we only found the env var byreading source — worth a line in the onboarding guide recommending it for
containerized/serverless deployments.
comment, not a warning. The E2E example dynamically
import()s amodule inside a function specifically so OpenTelemetry's
auto-instrumentation can patch it before use — because ES module imports
are hoisted, a top-of-file
importruns beforesovdev_initialize()evercould. The example's comment notes production apps should use a separate
instrumentation.js+node --requireinstead, but this isn't calledout as a warning anywhere prominent (onboarding guide, README
quick-start). A new integrator following the quick-start (not the E2E
example) could get silently-unpatched auto-instrumentation with no
warning at all.
guide. The README's "Compliance" section documents it clearly, but the
onboarding guide doesn't repeat the warning — worth a callout there too
("avoid ERROR/FATAL during initial integration testing — they may open
real incidents"), since onboarding is where a new integrator is most
likely to log a test ERROR before knowing this.
(a few lines + the library) added ~7.5 MB to an
esbuild --bundlesingle-file output. Not disqualifying at typical serverless scale, but
worth a line in the onboarding guide so integrators aren't surprised.
Dependency versions — 4 Dependabot alerts (2 high, 2 moderate)
1.0.2's pinned OpenTelemetry dependencies are behind their patchedversions:
^range@opentelemetry/sdk-node^0.55.00.217.0@opentelemetry/auto-instrumentations-node^0.51.00.75.0@opentelemetry/core(transitive)1.28.0/1.30.1across the tree2.8.0uuid(transitive, viagcp-metadata/gaxios)^9.0.111.1.1We checked the real-world exposure for each and none have an exploitable
path in our own deployment (the high-severity ones require the Prometheus
pull-exporter to be enabled, which we don't use; the moderate ones require
either inbound W3C
baggageheader extraction or a directuuid.v3/v5/v6call with an external buffer, neither of which we do) — but that's
deployment-specific luck, not something the package should rely on
integrators to verify individually. The current
^0.51.0/^0.55.0rangesdon't reach the patched versions, so this needs a version bump in a future
release rather than something we can resolve on our end.
A couple of things that worked well, for what it's worth
esbuild --bundle --platform=node --format=esm --target=node22bundledcleanly — ran identically bundled and unbundled against the real OTLP
endpoints, verified on the Grafana dashboard (both forms delivered real
telemetry). The feared auto-instrumentation-vs-single-file-bundle
conflict didn't materialize for a manual
sovdev_log/span usage pattern.company-lookup.tsE2E example is a genuinely good teachingartifact — more prescriptive than the quick-start alone (paired
start/success/error logs,
job_status/job_progressfor batch work,trace correlation via spans). Worth pointing new integrators to it
directly.
Happy to share more detail on any of the above if useful.