Skip to content

Commit fbbdd25

Browse files
committed
feat(cli,core): add opt-in dev-only telnet log streaming
Stream dev logs over a local telnet/TCP socket. `trigger dev` mirrors its terminal output on port 6700 by default (override with --telnet-logs-port or TRIGGER_DEV_TELNET_LOGS_PORT, 0 disables). webapp, supervisor, and coordinator each expose an opt-in stream gated on a per-service *_TELNET_LOGS_PORT env var. New @trigger.dev/core/v3/telnetLogServer module (localhost-only, backpressure-safe, plain-text) plus optional static Logger.onLog / SimpleStructuredLogger.onLog sinks.
1 parent 6563793 commit fbbdd25

14 files changed

Lines changed: 515 additions & 1 deletion

File tree

.changeset/telnet-dev-logs.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@trigger.dev/core": patch
3+
---
4+
5+
Add a `@trigger.dev/core/v3/telnetLogServer` module: the shared `TelnetLogServer` (localhost-only, backpressure-safe), `formatLogLine`, and `stripAnsi` helpers, plus an optional static `Logger.onLog` / `SimpleStructuredLogger.onLog` sink used to fan structured logs out to a local dev-only telnet/TCP stream.

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres?schema=publi
88
# See: https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#fields:~:text=the%20shadow%20database.-,directUrl,-No
99
DIRECT_URL=${DATABASE_URL}
1010
REMIX_APP_PORT=3030
11+
# Dev-only: stream the webapp's logs over a local telnet/TCP socket (nc localhost 6767). Uncomment to enable.
12+
# WEBAPP_TELNET_LOGS_PORT=6767
1113
APP_ENV=development
1214
APP_ORIGIN=http://localhost:3030
1315
ELECTRIC_ORIGIN=http://localhost:3060
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: supervisor
3+
type: feature
4+
---
5+
6+
Add an opt-in, dev-only telnet log stream: set `SUPERVISOR_TELNET_LOGS_PORT` (e.g. 6769) to tail this process's logs as plain text over a local TCP socket (`nc localhost 6769`). Bound to localhost; off unless the port is set.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: feature
4+
---
5+
6+
Add an opt-in, dev-only telnet log stream: set `WEBAPP_TELNET_LOGS_PORT` (e.g. 6767) to tail this process's logs as plain text over a local TCP socket (`nc localhost 6767`). Bound to localhost; off unless the port is set.

apps/supervisor/.env.example

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:3030/otel
1414

1515
# Optional settings
1616
DEBUG=1
17-
TRIGGER_DEQUEUE_INTERVAL_MS=1000
17+
TRIGGER_DEQUEUE_INTERVAL_MS=1000
18+
19+
# Dev-only: stream this process's logs over a local telnet/TCP socket (nc localhost 6769). Uncomment to enable.
20+
# SUPERVISOR_TELNET_LOGS_PORT=6769

apps/supervisor/src/env.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ export const Env = z
99
TRIGGER_WORKER_INSTANCE_NAME: z.string().default(randomUUID()),
1010
TRIGGER_WORKER_HEARTBEAT_INTERVAL_SECONDS: z.coerce.number().default(30),
1111

12+
// Opt-in, dev-only: stream this process's logs over a local telnet/TCP socket on this port.
13+
SUPERVISOR_TELNET_LOGS_PORT: z.coerce.number().optional(),
14+
1215
// Required settings
1316
TRIGGER_API_URL: z.string().url(),
1417
TRIGGER_WORKER_TOKEN: z.string(), // accepts file:// path to read from a file

apps/supervisor/src/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { SupervisorSession } from "@trigger.dev/core/v3/workers";
22
import { SimpleStructuredLogger } from "@trigger.dev/core/v3/utils/structuredLogger";
3+
import { formatLogLine, startTelnetLogServer } from "@trigger.dev/core/v3/telnetLogServer";
34
import { env } from "./env.js";
45
import { WorkloadServer } from "./workloadServer/index.js";
56
import type { WorkloadManagerOptions, WorkloadManager } from "./workloadManager/types.js";
@@ -749,5 +750,14 @@ class ManagedSupervisor {
749750
}
750751
}
751752

753+
// Opt-in, dev-only: mirror this process's structured logs to a local telnet/TCP stream.
754+
if (env.SUPERVISOR_TELNET_LOGS_PORT && env.SUPERVISOR_TELNET_LOGS_PORT > 0) {
755+
const telnetLogServer = startTelnetLogServer({
756+
port: env.SUPERVISOR_TELNET_LOGS_PORT,
757+
name: "supervisor",
758+
});
759+
SimpleStructuredLogger.onLog = (log) => telnetLogServer.broadcast(formatLogLine(log));
760+
}
761+
752762
const worker = new ManagedSupervisor();
753763
worker.start();

apps/webapp/app/env.server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ const EnvironmentSchema = z
139139
.optional(),
140140
ADMIN_EMAILS: z.string().refine(isValidRegex, "ADMIN_EMAILS must be a valid regex.").optional(),
141141
REMIX_APP_PORT: z.string().optional(),
142+
// Opt-in, dev-only: stream this process's logs over a local telnet/TCP socket on this port.
143+
// Read directly from process.env in server.ts (before this schema loads); declared here for discoverability.
144+
WEBAPP_TELNET_LOGS_PORT: z.coerce.number().optional(),
142145
LOGIN_ORIGIN: z.string().default("http://localhost:3030"),
143146
LOGIN_RATE_LIMITS_ENABLED: BoolEnv.default(true),
144147
APP_ORIGIN: z.string().default("http://localhost:3030"),

apps/webapp/app/services/logger.server.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { LogLevel } from "@trigger.dev/core/logger";
22
import { Logger } from "@trigger.dev/core/logger";
3+
import { patchConsoleToTelnet, startTelnetLogServer } from "@trigger.dev/core/v3/telnetLogServer";
34
import { sensitiveDataReplacer } from "./sensitiveDataReplacer";
45
import { AsyncLocalStorage } from "async_hooks";
56
import { getHttpContext } from "./httpAsyncStorage.server";
@@ -79,3 +80,19 @@ export const socketLogger = new Logger(
7980
return fields ? { ...fields } : {};
8081
}
8182
);
83+
84+
// Opt-in, dev-only: mirror this process's stdout to a local telnet/TCP stream.
85+
// We patch console (rather than the static Logger.onLog sink) so the stream also captures logs
86+
// from separate/bundled copies of the Logger — e.g. the enterprise SSO plugin, which bundles its
87+
// own @trigger.dev/core and logs via its own console.log, invisible to the webapp's onLog hook.
88+
const telnetLogsPort = process.env.WEBAPP_TELNET_LOGS_PORT
89+
? Number(process.env.WEBAPP_TELNET_LOGS_PORT)
90+
: undefined;
91+
if (telnetLogsPort && Number.isFinite(telnetLogsPort) && telnetLogsPort > 0) {
92+
const telnetGlobal = globalThis as typeof globalThis & { __webappTelnetLogs?: boolean };
93+
if (!telnetGlobal.__webappTelnetLogs) {
94+
telnetGlobal.__webappTelnetLogs = true;
95+
const telnetLogServer = startTelnetLogServer({ port: telnetLogsPort, name: "webapp" });
96+
patchConsoleToTelnet(telnetLogServer, { pretty: true });
97+
}
98+
}

packages/core/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"./v3/utils/omit": "./src/v3/utils/omit.ts",
4444
"./v3/utils/retries": "./src/v3/utils/retries.ts",
4545
"./v3/utils/structuredLogger": "./src/v3/utils/structuredLogger.ts",
46+
"./v3/telnetLogServer": "./src/v3/telnetLogServer.ts",
4647
"./v3/test": "./src/v3/test/index.ts",
4748
"./v3/zodfetch": "./src/v3/zodfetch.ts",
4849
"./v3/zodMessageHandler": "./src/v3/zodMessageHandler.ts",
@@ -124,6 +125,9 @@
124125
"v3/utils/structuredLogger": [
125126
"dist/commonjs/v3/utils/structuredLogger.d.ts"
126127
],
128+
"v3/telnetLogServer": [
129+
"dist/commonjs/v3/telnetLogServer.d.ts"
130+
],
127131
"v3/zodfetch": [
128132
"dist/commonjs/v3/zodfetch.d.ts"
129133
],
@@ -490,6 +494,17 @@
490494
"default": "./dist/commonjs/v3/utils/structuredLogger.js"
491495
}
492496
},
497+
"./v3/telnetLogServer": {
498+
"import": {
499+
"@triggerdotdev/source": "./src/v3/telnetLogServer.ts",
500+
"types": "./dist/esm/v3/telnetLogServer.d.ts",
501+
"default": "./dist/esm/v3/telnetLogServer.js"
502+
},
503+
"require": {
504+
"types": "./dist/commonjs/v3/telnetLogServer.d.ts",
505+
"default": "./dist/commonjs/v3/telnetLogServer.js"
506+
}
507+
},
493508
"./v3/test": {
494509
"import": {
495510
"@triggerdotdev/source": "./src/v3/test/index.ts",

0 commit comments

Comments
 (0)