Skip to content

Commit 8917d65

Browse files
committed
Add API spec for logger client integration into cdp-client
Specifies two changes: - Bundle cdplogger-client into cdp-client as studio.logger - Add client.logger() method using service-based discovery and proxy transport via makeServiceTransport (CDP 5.1+) Logger protocol is tunneled through the StudioAPI WebSocket, serving data behind authentication with no direct connection to the logger port.
1 parent ea72cfd commit 8917d65

1 file changed

Lines changed: 125 additions & 0 deletions

File tree

spec-logger-integration.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# JavaScript CDP Client: Logger Integration — API Spec
2+
3+
## Problem
4+
5+
Connecting to a CDP Logger requires manual discovery boilerplate:
6+
7+
```javascript
8+
const client = new studio.api.Client('host:7689', listener);
9+
client.find("App.CDPLogger").then(logger => {
10+
logger.subscribeToChildValues("ServerPort", port => {
11+
const loggerClient = new cdplogger.Client("host:" + port);
12+
// Now use loggerClient separately...
13+
});
14+
});
15+
```
16+
17+
This requires knowing the logger node path, the `ServerPort` child convention, extracting the hostname, and managing two independent client lifecycles. The direct WebSocket connection bypasses StudioAPI authentication and is blocked by browsers when the page is served over HTTPS. The logger client is also a separate npm package (`cdplogger-client`) with its own protobuf schema.
18+
19+
## Proposed API Changes
20+
21+
### 1. Bundle logger client into `cdp-client`
22+
23+
The logger client code moves into the `cdp-client` package. Direct construction via `new studio.logger.Client(endpoint)` remains available for cases where the endpoint is already known.
24+
25+
### 2. `client.logger()` auto-discovers via services
26+
27+
New method on `studio.api.Client` (CDP 5.1+):
28+
29+
```javascript
30+
const client = new studio.api.Client('host:7689', listener);
31+
const loggerClient = await client.logger();
32+
// loggerClient is ready to use — requestLoggedNodes(), requestDataPoints(), etc.
33+
```
34+
35+
Both CDPLogger and LogServer register as `websocketproxy` services with `proxy_type: "logserver"` via their shared `ServerRunner` class. The JS client already receives these via `ServicesNotification` and stores them in `availableServices`.
36+
37+
**Behavior:**
38+
39+
- `client.logger()` finds the first service with `proxy_type === 'logserver'` in `availableServices`, creates a service transport via `makeServiceTransport(serviceId)`, and passes it to the logger client. The logger protocol (`DBMessaging.Protobuf.Container`) is tunneled through the StudioAPI WebSocket via `ServiceMessage` — no direct connection to the logger port.
40+
- `client.logger(name)` filters by service name when multiple loggers exist. The service name is the logger's node path (e.g., `'App.CDPLogger'`).
41+
- An optional `timeout` (milliseconds) can be passed to reject if no matching service appears in time.
42+
- `client.loggers()` returns `Promise<Array<{name, metadata}>>` with all currently discovered logger services. Resolves after the first `ServicesNotification` response.
43+
- Returns `Promise<LoggerClient>`. If no matching logger service has been announced yet, the promise waits until one appears via `ServicesNotification`.
44+
45+
**Caching:**
46+
47+
- Repeated calls return the same cached instance.
48+
- A cached logger client whose transport has closed is evicted — the next call triggers fresh discovery.
49+
50+
**Lifecycle:**
51+
52+
- `client.close()` disconnects all cached logger clients, rejects any pending `client.logger()` promises, and clears the cache.
53+
- After `client.close()`, calls on a disconnected logger client reject immediately with `"Client is disconnected"`.
54+
- When the main StudioAPI connection drops, service transports are torn down.
55+
56+
---
57+
58+
## Use Case Examples
59+
60+
### Example 1: Query historical data
61+
62+
```javascript
63+
const studio = require("cdp-client");
64+
const client = new studio.api.Client("127.0.0.1:7689");
65+
66+
const logger = await client.logger();
67+
const limits = await logger.requestLogLimits();
68+
const points = await logger.requestDataPoints(
69+
['Temperature', 'Pressure'],
70+
limits.startS, limits.endS, 200 /* max points */, 0 /* no batch limit */
71+
);
72+
points.forEach(p => {
73+
const temp = p.value['Temperature'];
74+
console.log(new Date(p.timestamp * 1000), 'min:', temp.min, 'max:', temp.max);
75+
});
76+
```
77+
78+
### Example 2: Query events
79+
80+
```javascript
81+
const logger = await client.logger();
82+
const events = await logger.requestEvents({
83+
limit: 100,
84+
flags: studio.logger.Client.EventQueryFlags.NewestFirst
85+
});
86+
events.forEach(e => console.log(e.sender, e.data.Text));
87+
```
88+
89+
### Example 3: Multiple loggers — select by name
90+
91+
```javascript
92+
const logger = await client.logger('App.CDPLogger');
93+
const logServer = await client.logger('App.MyLogServer');
94+
```
95+
96+
---
97+
98+
## Code Organization
99+
100+
```
101+
JavascriptCDPClient/
102+
index.js
103+
studioapi.proto.js
104+
logger/
105+
logger-client.js
106+
container-pb.js
107+
package.json
108+
```
109+
110+
The logger client constructor is extended to also accept a service transport object. The service transport from `makeServiceTransport` provides the same interface as a WebSocket (`send`, `close`, `onopen`, `onmessage`, `onclose`, `onerror`).
111+
112+
## Migration Notes
113+
114+
No breaking changes. The recommended migration from standalone `cdplogger-client`:
115+
116+
```javascript
117+
// Before (direct connection, no authentication):
118+
const cdplogger = require("cdplogger-client");
119+
const loggerClient = new cdplogger.Client('127.0.0.1:17000');
120+
121+
// After (auto-discovery via proxy, with authentication):
122+
const studio = require("cdp-client");
123+
const client = new studio.api.Client("127.0.0.1:7689", listener);
124+
const loggerClient = await client.logger();
125+
```

0 commit comments

Comments
 (0)