@objlabs/trace
v0.1.0
Published
Secure trace/logging layer for ObjLabs projects
Downloads
102
Readme
@objlabs/trace
@objlabs/trace is a secure trace/logging layer for ObjLabs projects (Next.js / Node / browser).
It replaces raw console.* usage with a policy-driven, security‑aware trace API that can be
shared across all apps in a monorepo.
The goal is:
- Remove
console.*from application code (for secure coding compliance) - Centralize logging/trace behavior in one place
- Enforce masking of sensitive data
- Apply different behaviors per environment (
dev,staging,prod)
Features
Simple API
import { trace } from "@objlabs/trace"; trace.debug("something happened", { foo: "bar" }); trace.info("user:login", { userId }); trace.warn("api:slow", { ms: 1234 }); trace.error("unexpected", { error });Scopes & Context
const t = trace.scope("user:update").with({ ip: clientIp }); t.info("start", { userId }); t.error("failed", { error });Environment‑aware
dev:debugand above, verbose traces allowedstaging:infoand aboveprod:warnand above by default
Sensitive data redaction
- Keys like
password,token,secret,email,phone,ssn,rrnare automatically masked. - Circular references in data are safely handled.
- Keys like
Pluggable transports
- Node: JSON to
stdout(or custom transports) - Browser: dev can log to console, non‑dev sends to
/api/traceviasendBeacon/fetch
- Node: JSON to
Install
# from your private registry or local link
npm install @objlabs/trace
# or
pnpm add @objlabs/traceBasic Usage
1. Configure once at app bootstrap
In a Next.js app (App Router):
// apps/web/app/trace-setup.ts
import { configureTrace } from "@objlabs/trace";
import { defaultTransports } from "@objlabs/trace/transports";
configureTrace({
// env and level default from NODE_ENV / TRACE_ENV
transports: defaultTransports(),
// scopesEnabled: ["user:*", "order:create"], // optional, dev-only scope filter
});Then import this file once at the root layout:
// apps/web/app/layout.tsx
import "./trace-setup";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ko">
<body>{children}</body>
</html>
);
}2. Use trace in your code
// apps/web/app/api/users/route.ts
import { trace } from "@objlabs/trace";
export async function POST(req: Request) {
const body = await req.json();
const t = trace.scope("user:create").with({
ip: req.headers.get("x-forwarded-for"),
});
t.info("start", { email: body.email });
try {
// ... user creation logic
const userId = "123";
t.info("success", { userId });
return new Response("OK", { status: 201 });
} catch (err) {
t.error("failed", { error: String(err) });
return new Response("ERROR", { status: 500 });
}
}API
trace (singleton)
Default trace instance configured via configureTrace.
import { trace } from "@objlabs/trace";
trace.debug(message, data?);
trace.info(message, data?);
trace.warn(message, data?);
trace.error(message, data?);
trace.scope(name); // returns a child Trace with a scope
trace.with(context); // returns a child Trace with extra contextconfigureTrace(config: TraceConfig)
Configure global trace behavior once at bootstrap.
import { configureTrace } from "@objlabs/trace";
import type { TraceConfig } from "@objlabs/trace";
const config: TraceConfig = {
env: "dev" | "staging" | "prod", // optional, defaults from env vars
level: "debug" | "info" | "warn" | "error",
transports: [/* TraceTransport[] */],
redactor: (data) => data, // optional, defaults to built‑in redactor
scopesEnabled: ["user:*", "order:create"] | "*",
};
configureTrace(config);createTrace(config?: TraceConfig)
Create an isolated Trace instance (e.g. for tests or special pipelines).
import { createTrace } from "@objlabs/trace";
const testTrace = createTrace({
env: "dev",
level: "debug",
transports: [
(record) => {
// push to an in‑memory array for assertions
console.log("test record", record);
},
],
});Environment & Levels
env is resolved as:
TRACE_ENVif set- else
NODE_ENV - else
development
Mapping:
"production"→"prod""development"→"dev"- anything else →
"staging"
Default level per env:
dev→"debug"staging→"info"prod→"warn"
You can override via TraceConfig.level.
Sensitive Data Redaction
By default, the built‑in redactor:
Handles non‑object data transparently
Recursively walks objects/arrays
Masks values for keys containing:
password,passwdtoken,secretemailphone,telssn,rrn
Replaces circular references with
"[Circular]"
You can supply your own redactor function in TraceConfig to extend or replace this behavior.
Scopes
Scopes let you group traces by feature/domain:
trace.scope("user:login").info("start", { email });
trace.scope("user:login").error("failed", { reason });
trace.scope("order:create").debug("payload", payload);In dev, you can restrict which scopes actually emit traces
with scopesEnabled:
configureTrace({
scopesEnabled: ["user:*", "order:create"], // only these scopes are active
});In staging / prod, scope is recorded as metadata but does not
filter emission (level decides).
Secure Coding & console Policy
The recommended usage pattern is:
Application code must not use
console.*directly.Enforce via ESLint:
// .eslintrc.js module.exports = { rules: { "no-console": "error", }, };All logging/trace behavior goes through
@objlabs/trace.@objlabs/traceencapsulates:- Environment‑specific levels
- Sensitive data redaction
- Output destinations (stdout, HTTP, etc.)
- Optional browser behavior
This makes it much easier to comply with secure‑coding guidelines and pass static analysis that flags residual debugging code.
Extending Transports
Transports are simple functions that receive a TraceRecord:
import type { TraceRecord, TraceTransport } from "@objlabs/trace";
const sentryTransport: TraceTransport = (rec: TraceRecord) => {
if (rec.level === "error") {
// Example: integrate with Sentry / APM
// Sentry.captureMessage(rec.message, { extra: rec });
}
};Register via configureTrace:
import { configureTrace } from "@objlabs/trace";
import { defaultTransports } from "@objlabs/trace/transports";
configureTrace({
transports: [...defaultTransports(), sentryTransport],
});License
MIT (or your preferred internal license)
