Skip to content

feat(serve): add daemon file logger for qwen serve diagnostics #4548

@doudouOUC

Description

@doudouOUC

Background

qwen serve currently emits most daemon-layer diagnostics to process stderr. This includes bridge errors from sendBridgeError(...) in packages/cli/src/serve/server.ts, lifecycle/shutdown messages in packages/cli/src/serve/runQwenServe.ts, and ACP child stderr forwarded from packages/cli/src/serve/httpAcpBridge.ts with a [serve pid=... cwd=...] prefix.

That works when the operator explicitly redirects stderr or runs under a supervisor that captures stderr, but it is easy to miss in SDK/Desktop/daemon deployments. For example, when a client sees POST /session/:id/prompt return HTTP 500, the useful route/session/error context is often only available from the daemon stderr stream.

The existing createDebugLogger is not a drop-in replacement for this. It is session-scoped and depends on an active debug log session; the qwen serve daemon process starts before any session exists, so using it directly from serve code can silently drop daemon logs. ACP child telemetry/debug logging also does not fully cover daemon HTTP routing, bridge lifecycle, queueing, child stderr forwarding, or daemon startup/shutdown failures.

Related but distinct: #2014 requested a standalone structured error log for external monitoring. This issue is narrower: persist qwen serve daemon diagnostics so troubleshooting does not require manual stderr redirection.

Problem

Daemon deployments need a durable local log for serve-level failures. Today the recommended workaround is effectively to capture stderr, for example qwen serve 2>serve.log, or rely on systemd/Docker/journald. That is fragile for local SDK/Desktop usage and makes HTTP 500 investigation harder than necessary.

Proposal

Add a daemon-specific logger/sink initialized by runQwenServe.

Suggested behavior:

  • Write daemon logs under the runtime directory, for example ${QWEN_RUNTIME_DIR or ~/.qwen}/debug/daemon/<daemon-id>.log.
  • Use a stable daemon id derived from process/workspace/listen context, such as serve-<pid>-<workspaceHash>.
  • Keep stderr output for operator visibility in terminal, systemd, Docker, and Kubernetes logs; file logging should be additive, not a replacement.
  • Route serve diagnostics through a small helper that writes important lines to both stderr and the daemon log.
  • Persist QWEN_SERVE_DEBUG debug breadcrumbs to the same daemon log when enabled.
  • Persist ACP child stderr forwarding lines to the daemon log with the same attribution prefix currently sent to stderr.
  • Include enough context for triage: timestamp, level, route, session id if known, client id if known, workspace/cwd, child pid/channel id when available, and the error stack/message.
  • Avoid reusing session debug-log state in a way that changes the normal per-session debug/latest semantics, unless that behavior is explicitly designed and documented.

Acceptance criteria

  • Starting qwen serve creates or appends a daemon log file without requiring shell stderr redirection.
  • A generic HTTP 500 from POST /session/:id/prompt can be correlated in the daemon log by route and session id.
  • ACP child stderr lines that are currently forwarded to daemon stderr are also written to the daemon log.
  • Logging works before the first session is created and after all sessions are closed.
  • Existing stderr behavior remains intact for operators and process managers.
  • The log path and any opt-out/debug behavior are documented.

Non-goals

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions