gadget/docs/drone-logger.md

132 lines
4.7 KiB
Markdown

# Gadget Code: GadgetLogTransportSocket
GadgetLog now ships four transports out of the box: **Console**, **File**, **Socket**, and the abstract base. The socket transport (`GadgetLogTransportSocket`) transmits every log entry from `gadget-drone``gadget-code:backend``gadget-code:frontend` over Socket.IO, rendering live in the IDE's LogPanel.
## Message Flow
```
gadget-drone
│ GadgetLogTransportSocket.writeLog()
│ socket.emit("log", timestamp, component, level, message, metadata?)
gadget-code:backend (DroneSession.onLog)
│ SocketService.getCodeSessionByChatSessionId(chatSessionId)
│ codeSession.onLog(...)
gadget-code:backend (CodeSession.onLog)
│ socket.emit("log", timestamp, component, level, message, metadata?)
gadget-code:frontend (SocketClient)
│ raw socket "log" → internal "log:entry" event
│ { level, component, message, metadata, timestamp }
ChatSessionView.handleLogEntry
│ setLogs(...)
LogPanel — terminal-styled live log viewer
```
## Transport: `GadgetLogTransportSocket`
**File:** `packages/api/src/lib/log-transport-socket.ts`
Accepts a generic emit function (no Socket.IO dependency in `@gadget/api`):
```typescript
export type LogEmitFunction = (
event: string,
timestamp: Date,
component: GadgetComponent,
level: GadgetLogLevel,
message: string,
metadata?: unknown,
) => void;
```
`writeLog()` calls `this.emit("log", ...)` with the same parameters `GadgetLog.writeLog()` receives.
## Registration in gadget-drone
Registered in `gadget-drone.ts` `connectSocket()`, after the Socket.IO connection succeeds:
```typescript
const socketTransport = new GadgetLogTransportSocket((event, ...args) => {
(this.socket as any)?.emit(event, ...args);
});
GadgetLog.addDefaultTransport(socketTransport);
this.log.transports.push(socketTransport);
AgentService.log.transports.push(socketTransport);
AiService.log.transports.push(socketTransport);
PlatformService.log.transports.push(socketTransport);
```
The transport is injected into all existing loggers (main process + 3 services) and set as a default for future `GadgetLog` instances.
## Backend Routing
### DroneSession (`gadget-code/src/lib/drone-session.ts`)
- Registers `this.socket.on("log", this.onLog.bind(this))`
- `onLog()` guards on `this.chatSessionId`, looks up the `CodeSession` via `SocketService.getCodeSessionByChatSessionId()`, forwards the call.
### CodeSession (`gadget-code/src/lib/code-session.ts`)
- `onLog()` calls `this.socket.emit("log", timestamp, component, level, message, metadata)` forwards to the IDE.
## Frontend Bridging
### SocketClient (`gadget-code/frontend/src/lib/socket.ts`)
The raw Socket.IO `log` event is forwarded to the internal `log:entry` event system:
```typescript
this.socket.on("log", (timestamp, component, level, message, metadata) => {
this.emit("log:entry", {
level,
component: component.name,
message,
metadata,
timestamp: new Date(timestamp).getTime(),
});
});
```
### ChatSessionView
`handleLogEntry` callback builds a `LogEntry` with all fields and appends to the `logs` state array.
## LogPanel Display
**File:** `gadget-code/frontend/src/components/LogPanel.tsx`
Styled to match the Console Transport:
| Element | Console Color | Tailwind Class |
|---------|---------------|----------------|
| Timestamp | `darkGray` | `text-gray-600` |
| Level: debug | `darkGray` | `text-gray-500` |
| Level: info | `green` | `text-green-400` |
| Level: warn | `yellow` | `text-yellow-400` |
| Level: alert | `red` | `text-red-400` |
| Level: error | `bgRed` + `white` | `bg-red-800 text-white` |
| Level: crit | `bgRed` + `yellow` | `bg-red-800 text-yellow-300` |
| Level: fatal | `bgRed` + `darkGray` | `bg-red-800 text-gray-400` |
| Component | `cyan` | `text-cyan-400` |
| Message | `darkGray` | `text-text-secondary` |
Metadata is displayed as expandable JSON below the log line (toggled with `⊞`/`⊟`).
## Files Changed
| File | Action |
|------|--------|
| `packages/api/src/lib/log-transport-socket.ts` | **NEW** — socket transport |
| `packages/api/src/index.ts` | **MODIFY** — export new transport |
| `gadget-drone/src/gadget-drone.ts` | **MODIFY** — register transport on connect |
| `gadget-drone/src/lib/service.ts` | **MODIFY**`log` public for transport injection |
| `gadget-code/src/lib/drone-session.ts` | **MODIFY**`onLog` handler |
| `gadget-code/src/lib/code-session.ts` | **MODIFY**`onLog` forwarding |
| `gadget-code/frontend/src/lib/socket.ts` | **MODIFY** — bridge `log``log:entry` |
| `gadget-code/frontend/src/pages/ChatSessionView.tsx` | **MODIFY** — enriched `LogEntry` |
| `gadget-code/frontend/src/components/LogPanel.tsx` | **REWRITE** — console-styled display |