drtrace 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -4
- package/agents/daemon-method-selection.md +73 -1
- package/agents/log-analysis.md +15 -14
- package/agents/log-help.md +2 -2
- package/dist/browser.d.ts +28 -0
- package/dist/browser.js +91 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/init.d.ts +2 -0
- package/dist/init.js +23 -18
- package/dist/logger.d.ts +7 -0
- package/dist/logger.js +30 -4
- package/dist/node.d.ts +13 -0
- package/dist/node.js +67 -0
- package/dist/resources/agents/daemon-method-selection.md +73 -1
- package/dist/resources/agents/log-analysis.md +15 -14
- package/dist/resources/agents/log-help.md +2 -2
- package/dist/resources/cpp/drtrace_sink.hpp +1 -0
- package/dist/transport.js +5 -1
- package/dist/types.d.ts +8 -2
- package/package.json +20 -3
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ This runs an interactive setup wizard that creates the `_drtrace/` configuration
|
|
|
23
23
|
- Configuration guide (`README.md`)
|
|
24
24
|
- Default agent specification
|
|
25
25
|
|
|
26
|
-
###
|
|
26
|
+
### Node.js Usage
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
29
|
import { DrTrace } from 'drtrace';
|
|
@@ -39,7 +39,6 @@ const client = DrTrace.init();
|
|
|
39
39
|
// flushIntervalMs: 1000,
|
|
40
40
|
// maxRetries: 3,
|
|
41
41
|
// maxQueueSize: 10000,
|
|
42
|
-
// timeoutMs: 5000,
|
|
43
42
|
// });
|
|
44
43
|
|
|
45
44
|
// Attach to console
|
|
@@ -50,6 +49,48 @@ console.log('This is captured by DrTrace');
|
|
|
50
49
|
console.error('Errors are also captured');
|
|
51
50
|
```
|
|
52
51
|
|
|
52
|
+
### Browser Usage (React, Vue, etc.)
|
|
53
|
+
|
|
54
|
+
In browser environments, you must provide `applicationId` and `daemonUrl` explicitly since the browser cannot read config files from the filesystem.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { DrTrace } from 'drtrace'; // Auto-selects browser entry point
|
|
58
|
+
|
|
59
|
+
// Browser requires explicit options (no config file loading)
|
|
60
|
+
const client = DrTrace.init({
|
|
61
|
+
applicationId: 'my-react-app',
|
|
62
|
+
daemonUrl: 'http://localhost:8001',
|
|
63
|
+
moduleName: 'frontend', // Optional: helps identify log source
|
|
64
|
+
batchSize: 50,
|
|
65
|
+
flushIntervalMs: 1000,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Attach to console
|
|
69
|
+
client.attachToConsole();
|
|
70
|
+
|
|
71
|
+
// Objects are serialized properly
|
|
72
|
+
console.log({ user: 'john', action: 'login' }); // Logs as JSON
|
|
73
|
+
console.error('Something went wrong', new Error('Details'));
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Important for Browser:**
|
|
77
|
+
- `applicationId` is **required** - throws error if missing
|
|
78
|
+
- `daemonUrl` is **required** - throws error if missing
|
|
79
|
+
- CORS must be enabled on the daemon (enabled by default)
|
|
80
|
+
- Objects and errors are automatically serialized to JSON
|
|
81
|
+
|
|
82
|
+
#### CORS Configuration
|
|
83
|
+
|
|
84
|
+
The DrTrace daemon allows all origins by default. To restrict origins:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Allow specific origins
|
|
88
|
+
export DRTRACE_CORS_ORIGINS="http://localhost:3000,https://myapp.com"
|
|
89
|
+
|
|
90
|
+
# Start daemon
|
|
91
|
+
uvicorn drtrace_service.api:app --host localhost --port 8001
|
|
92
|
+
```
|
|
93
|
+
|
|
53
94
|
## Starting the DrTrace Daemon
|
|
54
95
|
|
|
55
96
|
**Important**: The DrTrace daemon must be running before your application can send logs.
|
|
@@ -155,13 +196,13 @@ Create a new DrTrace client instance.
|
|
|
155
196
|
|
|
156
197
|
**Options:**
|
|
157
198
|
- `applicationId` (required) - Unique application identifier
|
|
158
|
-
- `daemonUrl` (optional) - DrTrace daemon URL (default: `http://localhost:8001`)
|
|
199
|
+
- `daemonUrl` (required in browser, optional in Node.js) - DrTrace daemon URL (default: `http://localhost:8001`)
|
|
200
|
+
- `moduleName` (optional) - Module/component name for log grouping (default: `'default'`)
|
|
159
201
|
- `enabled` (optional) - Enable/disable DrTrace (default: `true`)
|
|
160
202
|
- `batchSize` (optional) - Batch size for log batching (default: `50`)
|
|
161
203
|
- `flushIntervalMs` (optional) - Flush interval in milliseconds (default: `1000`)
|
|
162
204
|
- `maxRetries` (optional) - Retry attempts for failed sends with exponential backoff (default: `3`)
|
|
163
205
|
- `maxQueueSize` (optional) - Maximum queued log entries before oldest entries are dropped (default: `10000`)
|
|
164
|
-
- `timeoutMs` (optional) - Request timeout per batch in milliseconds (default: `5000`)
|
|
165
206
|
|
|
166
207
|
### `client.attachToConsole()`
|
|
167
208
|
|
|
@@ -288,6 +288,78 @@ def interact_with_daemon(query: str) -> str:
|
|
|
288
288
|
|
|
289
289
|
---
|
|
290
290
|
|
|
291
|
+
## Important: Timestamps Are UTC
|
|
292
|
+
|
|
293
|
+
All timestamps in DrTrace API are **UTC Unix timestamps**:
|
|
294
|
+
|
|
295
|
+
| Field/Param | Format | Timezone |
|
|
296
|
+
|-------------|--------|----------|
|
|
297
|
+
| `ts` (in logs) | Unix float | UTC |
|
|
298
|
+
| `start_ts`, `end_ts` | Unix float | UTC |
|
|
299
|
+
| `since`, `until` | Relative or ISO 8601 | UTC |
|
|
300
|
+
|
|
301
|
+
**Key Rules**:
|
|
302
|
+
- ISO 8601 without timezone (e.g., `2025-12-31T02:44:03`) is interpreted as **UTC**, not local time
|
|
303
|
+
- Relative times (`5m`, `1h`) are relative to server's current UTC time
|
|
304
|
+
- To query with local time, include timezone offset: `2025-12-31T09:44:03+07:00`
|
|
305
|
+
|
|
306
|
+
### Converting Local Time to UTC
|
|
307
|
+
|
|
308
|
+
**Python:**
|
|
309
|
+
```python
|
|
310
|
+
from datetime import datetime, timezone, timedelta
|
|
311
|
+
|
|
312
|
+
# Local time (e.g., 2025-12-31 09:44:03 in GMT+7)
|
|
313
|
+
local_time = datetime(2025, 12, 31, 9, 44, 3)
|
|
314
|
+
|
|
315
|
+
# Method 1: If you know your timezone offset
|
|
316
|
+
local_tz = timezone(timedelta(hours=7)) # GMT+7
|
|
317
|
+
local_aware = local_time.replace(tzinfo=local_tz)
|
|
318
|
+
utc_time = local_aware.astimezone(timezone.utc)
|
|
319
|
+
unix_ts = utc_time.timestamp()
|
|
320
|
+
print(f"UTC Unix timestamp: {unix_ts}")
|
|
321
|
+
|
|
322
|
+
# Method 2: Using system timezone
|
|
323
|
+
import time
|
|
324
|
+
unix_ts = time.mktime(local_time.timetuple())
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Bash:**
|
|
328
|
+
```bash
|
|
329
|
+
# Convert local time to Unix timestamp
|
|
330
|
+
date -d "2025-12-31 09:44:03" +%s
|
|
331
|
+
|
|
332
|
+
# Convert with explicit timezone
|
|
333
|
+
TZ=UTC date -d "2025-12-31T02:44:03" +%s
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### API Query Examples with Timezone
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Option 1: Include timezone in ISO 8601 (recommended for local time)
|
|
340
|
+
curl "http://localhost:8001/logs/query?since=2025-12-31T09:44:03%2B07:00"
|
|
341
|
+
|
|
342
|
+
# Option 2: Use relative time (always relative to server UTC time)
|
|
343
|
+
curl "http://localhost:8001/logs/query?since=5m"
|
|
344
|
+
|
|
345
|
+
# Option 3: Convert to UTC Unix timestamp first
|
|
346
|
+
UTC_TS=$(TZ=UTC date -d "2025-12-31T02:44:03" +%s)
|
|
347
|
+
curl "http://localhost:8001/logs/query?start_ts=$UTC_TS"
|
|
348
|
+
|
|
349
|
+
# Option 4: Use ISO 8601 in UTC (note: no timezone = UTC)
|
|
350
|
+
curl "http://localhost:8001/logs/query?since=2025-12-31T02:44:03"
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Common Timezone Pitfalls
|
|
354
|
+
|
|
355
|
+
1. **ISO 8601 Without Timezone**: Interpreted as UTC, not local time. If you pass `2025-12-31T09:44:03` thinking it's local 9:44 AM, it will be treated as 9:44 AM UTC.
|
|
356
|
+
|
|
357
|
+
2. **Server vs Client Timezone**: If your server is in a different timezone than your client, always use explicit UTC timestamps or include timezone offsets.
|
|
358
|
+
|
|
359
|
+
3. **Relative Times**: `since=5m` means 5 minutes before server's current UTC time, regardless of your local timezone.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
291
363
|
## Related Documentation
|
|
292
364
|
|
|
293
365
|
- `docs/daemon-interaction-guide.md` - OpenAPI discovery details
|
|
@@ -295,4 +367,4 @@ def interact_with_daemon(query: str) -> str:
|
|
|
295
367
|
|
|
296
368
|
---
|
|
297
369
|
|
|
298
|
-
**Last Updated**: 2025-12-
|
|
370
|
+
**Last Updated**: 2025-12-31
|
package/agents/log-analysis.md
CHANGED
|
@@ -11,24 +11,25 @@ You must fully embody this agent's persona and follow all activation instruction
|
|
|
11
11
|
<step n="1">Load persona from this current agent file (already in context)</step>
|
|
12
12
|
<step n="2">Remember: You are a Log Analysis Specialist</step>
|
|
13
13
|
<step n="3">READ the entire story file BEFORE any analysis - understand the query parsing rules</step>
|
|
14
|
-
<step n="4">When processing a user query, try methods in this order:
|
|
15
|
-
|
|
16
|
-
**Method 1 (Preferred)**:
|
|
14
|
+
<step n="4">When processing a user query, try methods in this order (see `agents/daemon-method-selection.md` for details):
|
|
15
|
+
|
|
16
|
+
**Method 1 (Preferred)**: HTTP/curl
|
|
17
|
+
- Simple, no Python dependencies, works in any environment
|
|
18
|
+
- Check status: `GET http://localhost:8001/status`
|
|
19
|
+
- Query logs: `GET http://localhost:8001/logs/query?since=5m&application_id=X`
|
|
20
|
+
- Analysis: `GET http://localhost:8001/analysis/why?application_id=X&since=5m`
|
|
21
|
+
- **CRITICAL**: First fetch `/openapi.json` to discover field names (e.g., timestamp is `ts`, NOT `timestamp`)
|
|
22
|
+
|
|
23
|
+
**Method 2 (Fallback)**: Python SDK
|
|
24
|
+
- Use when HTTP is blocked or you need async features
|
|
17
25
|
- Try: `from drtrace_service.agent_interface import process_agent_query, check_daemon_status`
|
|
18
|
-
-
|
|
26
|
+
- Use `response = await process_agent_query(user_query)` or `asyncio.run(process_agent_query(user_query))`
|
|
19
27
|
- Return the response string directly (it's already formatted markdown)
|
|
20
|
-
|
|
21
|
-
**Method 2 (Fallback)**: HTTP API
|
|
22
|
-
- If Python import fails: Use HTTP requests to call DrTrace API endpoints
|
|
23
|
-
- **CRITICAL**: First fetch `/openapi.json` to discover field names (e.g., timestamp is `ts`, NOT `timestamp`)
|
|
24
|
-
- Check status: `GET http://localhost:8001/status`
|
|
25
|
-
- For analysis: `GET http://localhost:8001/analysis/why?application_id=X&start_ts=Y&end_ts=Z`
|
|
26
|
-
- Parse the JSON response using field names from OpenAPI schema
|
|
27
|
-
|
|
28
|
+
|
|
28
29
|
**Method 3 (Last resort)**: CLI commands
|
|
29
|
-
- If both
|
|
30
|
+
- If both HTTP and Python fail: Execute `python -m drtrace_service why --application-id X --since 5m`
|
|
30
31
|
- Parse the CLI output and format for the user
|
|
31
|
-
|
|
32
|
+
|
|
32
33
|
**Important**: Always check daemon status first. If daemon is unavailable, return clear error message with next steps.
|
|
33
34
|
</step>
|
|
34
35
|
<step n="5">If information is missing, ask the user for clarification with helpful suggestions</step>
|
package/agents/log-help.md
CHANGED
|
@@ -11,7 +11,7 @@ You must fully embody this agent's persona and follow all activation instruction
|
|
|
11
11
|
<step n="1">Load persona from this current agent file (already in context)</step>
|
|
12
12
|
<step n="2">Remember: You are a Setup Guide Assistant for DrTrace</step>
|
|
13
13
|
<step n="3">Your primary mission is to walk users through DrTrace setup step-by-step using the help APIs and setup guide, not to guess or skip steps</step>
|
|
14
|
-
<step n="4">ALWAYS prefer Method 1 (
|
|
14
|
+
<step n="4">ALWAYS prefer Method 1 (HTTP/curl) → then Method 2 (Python SDK) → then Method 3 (CLI) in that exact order. See `agents/daemon-method-selection.md` for details.</step>
|
|
15
15
|
<step n="5">For each user interaction, clearly state the current step, what to do next, and how to verify it worked</step>
|
|
16
16
|
<step n="6">When calling help APIs, use:
|
|
17
17
|
- `start_setup_guide(language, project_root)` to begin or restart a guide
|
|
@@ -32,7 +32,7 @@ You must fully embody this agent's persona and follow all activation instruction
|
|
|
32
32
|
<r>NEVER skip verification or pretend steps are complete; use the setup guide and help APIs as the source of truth</r>
|
|
33
33
|
<r>ALWAYS explain what you are doing when progressing steps or troubleshooting issues</r>
|
|
34
34
|
<r>Display menu items exactly as defined in the menu section and in the order given</r>
|
|
35
|
-
<r>Prefer
|
|
35
|
+
<r>Prefer HTTP/curl, then Python SDK, then CLI in that order; explain fallbacks when switching methods</r>
|
|
36
36
|
</rules>
|
|
37
37
|
</activation>
|
|
38
38
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ClientOptions, LogLevel } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* DrTrace client for browser environments.
|
|
4
|
+
*
|
|
5
|
+
* Unlike the Node.js client, this does NOT load configuration from files.
|
|
6
|
+
* All options must be passed explicitly to init().
|
|
7
|
+
*/
|
|
8
|
+
export declare class DrTrace {
|
|
9
|
+
private queue;
|
|
10
|
+
private logger;
|
|
11
|
+
private enabled;
|
|
12
|
+
private constructor();
|
|
13
|
+
/**
|
|
14
|
+
* Initialize DrTrace for browser environments.
|
|
15
|
+
* Unlike Node.js, browser does not load config from files.
|
|
16
|
+
* All options must be passed explicitly.
|
|
17
|
+
*
|
|
18
|
+
* @param opts - Client options (applicationId and daemonUrl are required)
|
|
19
|
+
* @throws Error if applicationId or daemonUrl are not provided
|
|
20
|
+
*/
|
|
21
|
+
static init(opts: ClientOptions): DrTrace;
|
|
22
|
+
attachToConsole(): void;
|
|
23
|
+
detachFromConsole(): void;
|
|
24
|
+
log(message: string, level?: LogLevel, context?: Record<string, unknown>): void;
|
|
25
|
+
error(message: string, context?: Record<string, unknown>): void;
|
|
26
|
+
shutdown(): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export * from './types';
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.DrTrace = void 0;
|
|
18
|
+
const transport_1 = require("./transport");
|
|
19
|
+
const queue_1 = require("./queue");
|
|
20
|
+
const logger_1 = require("./logger");
|
|
21
|
+
/**
|
|
22
|
+
* DrTrace client for browser environments.
|
|
23
|
+
*
|
|
24
|
+
* Unlike the Node.js client, this does NOT load configuration from files.
|
|
25
|
+
* All options must be passed explicitly to init().
|
|
26
|
+
*/
|
|
27
|
+
class DrTrace {
|
|
28
|
+
constructor(opts) {
|
|
29
|
+
const transport = new transport_1.Transport({
|
|
30
|
+
daemonUrl: opts.daemonUrl,
|
|
31
|
+
maxRetries: opts.maxRetries ?? 3,
|
|
32
|
+
timeoutMs: 5000,
|
|
33
|
+
});
|
|
34
|
+
this.queue = new queue_1.LogQueue({
|
|
35
|
+
transport,
|
|
36
|
+
batchSize: opts.batchSize ?? 50,
|
|
37
|
+
flushIntervalMs: opts.flushIntervalMs ?? 1000,
|
|
38
|
+
maxQueueSize: opts.maxQueueSize ?? 10000,
|
|
39
|
+
});
|
|
40
|
+
this.queue.start();
|
|
41
|
+
this.enabled = opts.enabled ?? true;
|
|
42
|
+
this.logger = new logger_1.DrTraceLogger({
|
|
43
|
+
queue: this.queue,
|
|
44
|
+
applicationId: opts.applicationId,
|
|
45
|
+
moduleName: opts.moduleName,
|
|
46
|
+
logLevel: (opts.logLevel ?? 'info'),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Initialize DrTrace for browser environments.
|
|
51
|
+
* Unlike Node.js, browser does not load config from files.
|
|
52
|
+
* All options must be passed explicitly.
|
|
53
|
+
*
|
|
54
|
+
* @param opts - Client options (applicationId and daemonUrl are required)
|
|
55
|
+
* @throws Error if applicationId or daemonUrl are not provided
|
|
56
|
+
*/
|
|
57
|
+
static init(opts) {
|
|
58
|
+
if (!opts.applicationId) {
|
|
59
|
+
throw new Error('applicationId is required for browser usage');
|
|
60
|
+
}
|
|
61
|
+
if (!opts.daemonUrl) {
|
|
62
|
+
throw new Error('daemonUrl is required for browser usage');
|
|
63
|
+
}
|
|
64
|
+
return new DrTrace(opts);
|
|
65
|
+
}
|
|
66
|
+
attachToConsole() {
|
|
67
|
+
if (!this.enabled)
|
|
68
|
+
return;
|
|
69
|
+
this.logger.attachToConsole();
|
|
70
|
+
}
|
|
71
|
+
detachFromConsole() {
|
|
72
|
+
this.logger.detachFromConsole();
|
|
73
|
+
}
|
|
74
|
+
log(message, level = 'info', context) {
|
|
75
|
+
if (!this.enabled)
|
|
76
|
+
return;
|
|
77
|
+
this.logger.log(level, message, context);
|
|
78
|
+
}
|
|
79
|
+
error(message, context) {
|
|
80
|
+
if (!this.enabled)
|
|
81
|
+
return;
|
|
82
|
+
this.logger.log('error', message, context);
|
|
83
|
+
}
|
|
84
|
+
async shutdown() {
|
|
85
|
+
await this.queue.flush();
|
|
86
|
+
this.queue.stop();
|
|
87
|
+
this.detachFromConsole();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.DrTrace = DrTrace;
|
|
91
|
+
__exportStar(require("./types"), exports);
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -15,8 +15,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.loadConfig = exports.DrTrace = void 0;
|
|
18
|
-
var
|
|
19
|
-
Object.defineProperty(exports, "DrTrace", { enumerable: true, get: function () { return
|
|
18
|
+
var node_1 = require("./node");
|
|
19
|
+
Object.defineProperty(exports, "DrTrace", { enumerable: true, get: function () { return node_1.DrTrace; } });
|
|
20
20
|
var config_1 = require("./config");
|
|
21
21
|
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
|
|
22
22
|
__exportStar(require("./types"), exports);
|
package/dist/init.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare class ProjectInitializer {
|
|
|
12
12
|
private projectRoot;
|
|
13
13
|
private drtraceDir;
|
|
14
14
|
private configPath;
|
|
15
|
+
private copiedAgentFiles;
|
|
15
16
|
constructor(projectRoot?: string);
|
|
16
17
|
/**
|
|
17
18
|
* Run the interactive initialization workflow
|
|
@@ -57,6 +58,7 @@ export declare class ProjectInitializer {
|
|
|
57
58
|
private copyAgentSpec;
|
|
58
59
|
/**
|
|
59
60
|
* Recursively copy all files from sourceDir to targetDir
|
|
61
|
+
* Returns list of relative file paths copied (for summary display)
|
|
60
62
|
*/
|
|
61
63
|
private copyAgentsRecursive;
|
|
62
64
|
/**
|
package/dist/init.js
CHANGED
|
@@ -49,6 +49,8 @@ const prompts_1 = __importDefault(require("prompts"));
|
|
|
49
49
|
const config_schema_1 = require("./config-schema");
|
|
50
50
|
class ProjectInitializer {
|
|
51
51
|
constructor(projectRoot = process.cwd()) {
|
|
52
|
+
// Track copied agent files for summary display
|
|
53
|
+
this.copiedAgentFiles = [];
|
|
52
54
|
this.projectRoot = projectRoot;
|
|
53
55
|
this.drtraceDir = path.join(projectRoot, "_drtrace");
|
|
54
56
|
this.configPath = path.join(this.drtraceDir, "config.json");
|
|
@@ -260,8 +262,9 @@ class ProjectInitializer {
|
|
|
260
262
|
console.warn("⚠️ Could not find agents directory");
|
|
261
263
|
return;
|
|
262
264
|
}
|
|
263
|
-
// Copy all files recursively
|
|
264
|
-
this.copyAgentsRecursive(agentsDir, path.join(this.drtraceDir, "agents"));
|
|
265
|
+
// Copy all files recursively and track copied files
|
|
266
|
+
const copiedFiles = this.copyAgentsRecursive(agentsDir, path.join(this.drtraceDir, "agents"));
|
|
267
|
+
this.copiedAgentFiles.push(...copiedFiles);
|
|
265
268
|
}
|
|
266
269
|
catch (error) {
|
|
267
270
|
console.warn(`⚠️ Could not copy agent files: ${error}`);
|
|
@@ -269,34 +272,35 @@ class ProjectInitializer {
|
|
|
269
272
|
}
|
|
270
273
|
/**
|
|
271
274
|
* Recursively copy all files from sourceDir to targetDir
|
|
275
|
+
* Returns list of relative file paths copied (for summary display)
|
|
272
276
|
*/
|
|
273
|
-
copyAgentsRecursive(sourceDir, targetDir) {
|
|
277
|
+
copyAgentsRecursive(sourceDir, targetDir, basePath = "") {
|
|
274
278
|
if (!fs.existsSync(targetDir)) {
|
|
275
279
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
276
280
|
}
|
|
277
281
|
const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
|
|
278
|
-
|
|
282
|
+
const copiedFiles = [];
|
|
279
283
|
for (const entry of entries) {
|
|
280
284
|
const srcPath = path.join(sourceDir, entry.name);
|
|
281
285
|
const destPath = path.join(targetDir, entry.name);
|
|
286
|
+
const relativePath = basePath ? path.join(basePath, entry.name) : entry.name;
|
|
282
287
|
if (entry.isDirectory()) {
|
|
283
288
|
// Recursively copy directories
|
|
284
|
-
this.copyAgentsRecursive(srcPath, destPath);
|
|
289
|
+
const subCopied = this.copyAgentsRecursive(srcPath, destPath, relativePath);
|
|
290
|
+
copiedFiles.push(...subCopied);
|
|
285
291
|
}
|
|
286
292
|
else {
|
|
287
293
|
// Copy file (no renaming needed - files are already named correctly)
|
|
288
294
|
fs.copyFileSync(srcPath, destPath);
|
|
289
|
-
|
|
290
|
-
console.log(`✓ Copied ${
|
|
295
|
+
copiedFiles.push(relativePath);
|
|
296
|
+
console.log(`✓ Copied ${relativePath}`);
|
|
291
297
|
}
|
|
292
298
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (!relativeSource.includes("..")) {
|
|
297
|
-
console.log(`✓ Successfully copied ${copiedCount} file(s) from agents/`);
|
|
298
|
-
}
|
|
299
|
+
// Print summary only at top level
|
|
300
|
+
if (!basePath && copiedFiles.length > 0) {
|
|
301
|
+
console.log(`✓ Successfully copied ${copiedFiles.length} file(s) from agents/`);
|
|
299
302
|
}
|
|
303
|
+
return copiedFiles;
|
|
300
304
|
}
|
|
301
305
|
/**
|
|
302
306
|
* Copy framework-specific integration guides to _drtrace/agents/integration-guides/
|
|
@@ -781,11 +785,12 @@ python -m drtrace_service status
|
|
|
781
785
|
}
|
|
782
786
|
console.log(` • ${path.join(this.drtraceDir, ".env.example")}`);
|
|
783
787
|
console.log(` • ${path.join(this.drtraceDir, "README.md")}`);
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
console.log(
|
|
787
|
-
|
|
788
|
-
|
|
788
|
+
// List all copied agent files (includes integration-guides/)
|
|
789
|
+
if (this.copiedAgentFiles.length > 0) {
|
|
790
|
+
console.log("\n📋 Agent Files:");
|
|
791
|
+
for (const agentFile of this.copiedAgentFiles.sort()) {
|
|
792
|
+
console.log(` • ${path.join(this.drtraceDir, "agents", agentFile)}`);
|
|
793
|
+
}
|
|
789
794
|
}
|
|
790
795
|
console.log("\n📖 Next Steps:");
|
|
791
796
|
console.log(` 1. Review ${this.configPath}`);
|
package/dist/logger.d.ts
CHANGED
|
@@ -3,13 +3,20 @@ import { LogQueue } from './queue';
|
|
|
3
3
|
export declare class DrTraceLogger {
|
|
4
4
|
private queue;
|
|
5
5
|
private applicationId;
|
|
6
|
+
private moduleName;
|
|
6
7
|
private logLevel;
|
|
7
8
|
private originalConsole?;
|
|
8
9
|
constructor(opts: {
|
|
9
10
|
queue: LogQueue;
|
|
10
11
|
applicationId: string;
|
|
12
|
+
moduleName?: string;
|
|
11
13
|
logLevel: LogLevel;
|
|
12
14
|
});
|
|
15
|
+
/**
|
|
16
|
+
* Serialize a value to a string suitable for logging.
|
|
17
|
+
* Handles objects, arrays, errors, and primitives correctly.
|
|
18
|
+
*/
|
|
19
|
+
private serialize;
|
|
13
20
|
attachToConsole(): void;
|
|
14
21
|
detachFromConsole(): void;
|
|
15
22
|
log(level: LogLevel, message: string, context?: Record<string, unknown>): void;
|
package/dist/logger.js
CHANGED
|
@@ -5,15 +5,40 @@ class DrTraceLogger {
|
|
|
5
5
|
constructor(opts) {
|
|
6
6
|
this.queue = opts.queue;
|
|
7
7
|
this.applicationId = opts.applicationId;
|
|
8
|
+
this.moduleName = opts.moduleName || 'default';
|
|
8
9
|
this.logLevel = opts.logLevel || 'info';
|
|
9
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Serialize a value to a string suitable for logging.
|
|
13
|
+
* Handles objects, arrays, errors, and primitives correctly.
|
|
14
|
+
*/
|
|
15
|
+
serialize(value) {
|
|
16
|
+
if (value === null)
|
|
17
|
+
return 'null';
|
|
18
|
+
if (value === undefined)
|
|
19
|
+
return 'undefined';
|
|
20
|
+
if (typeof value === 'string')
|
|
21
|
+
return value;
|
|
22
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
23
|
+
return String(value);
|
|
24
|
+
if (value instanceof Error) {
|
|
25
|
+
return value.stack || `${value.name}: ${value.message}`;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
return JSON.stringify(value);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Handle circular references gracefully
|
|
32
|
+
return String(value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
10
35
|
attachToConsole() {
|
|
11
36
|
if (this.originalConsole)
|
|
12
37
|
return;
|
|
13
38
|
this.originalConsole = { log: console.log, error: console.error };
|
|
14
39
|
console.log = (...args) => {
|
|
15
40
|
try {
|
|
16
|
-
this.log('info', args.map(
|
|
41
|
+
this.log('info', args.map((arg) => this.serialize(arg)).join(' '));
|
|
17
42
|
}
|
|
18
43
|
catch {
|
|
19
44
|
// Silently ignore logging errors
|
|
@@ -22,7 +47,7 @@ class DrTraceLogger {
|
|
|
22
47
|
};
|
|
23
48
|
console.error = (...args) => {
|
|
24
49
|
try {
|
|
25
|
-
this.log('error', args.map(
|
|
50
|
+
this.log('error', args.map((arg) => this.serialize(arg)).join(' '));
|
|
26
51
|
}
|
|
27
52
|
catch {
|
|
28
53
|
// Silently ignore logging errors
|
|
@@ -39,8 +64,9 @@ class DrTraceLogger {
|
|
|
39
64
|
}
|
|
40
65
|
log(level, message, context) {
|
|
41
66
|
const event = {
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
ts: Date.now() / 1000, // Unix timestamp as float (seconds.milliseconds)
|
|
68
|
+
application_id: this.applicationId,
|
|
69
|
+
module_name: this.moduleName,
|
|
44
70
|
level,
|
|
45
71
|
message,
|
|
46
72
|
context,
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ClientOptions, LogLevel } from './types';
|
|
2
|
+
export declare class DrTrace {
|
|
3
|
+
private queue;
|
|
4
|
+
private logger;
|
|
5
|
+
private enabled;
|
|
6
|
+
private constructor();
|
|
7
|
+
static init(opts?: Partial<ClientOptions>): DrTrace;
|
|
8
|
+
attachToConsole(): void;
|
|
9
|
+
detachFromConsole(): void;
|
|
10
|
+
log(message: string, level?: LogLevel, context?: Record<string, unknown>): void;
|
|
11
|
+
error(message: string, context?: Record<string, unknown>): void;
|
|
12
|
+
shutdown(): Promise<void>;
|
|
13
|
+
}
|
package/dist/node.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DrTrace = void 0;
|
|
4
|
+
const config_1 = require("./config");
|
|
5
|
+
const transport_1 = require("./transport");
|
|
6
|
+
const queue_1 = require("./queue");
|
|
7
|
+
const logger_1 = require("./logger");
|
|
8
|
+
class DrTrace {
|
|
9
|
+
constructor(opts) {
|
|
10
|
+
const transport = new transport_1.Transport({
|
|
11
|
+
daemonUrl: opts.daemonUrl,
|
|
12
|
+
maxRetries: opts.maxRetries ?? 3,
|
|
13
|
+
timeoutMs: 5000,
|
|
14
|
+
});
|
|
15
|
+
this.queue = new queue_1.LogQueue({
|
|
16
|
+
transport,
|
|
17
|
+
batchSize: opts.batchSize ?? 50,
|
|
18
|
+
flushIntervalMs: opts.flushIntervalMs ?? 1000,
|
|
19
|
+
maxQueueSize: opts.maxQueueSize ?? 10000,
|
|
20
|
+
});
|
|
21
|
+
this.queue.start();
|
|
22
|
+
this.enabled = opts.enabled ?? true;
|
|
23
|
+
this.logger = new logger_1.DrTraceLogger({
|
|
24
|
+
queue: this.queue,
|
|
25
|
+
applicationId: opts.applicationId,
|
|
26
|
+
moduleName: opts.moduleName,
|
|
27
|
+
logLevel: (opts.logLevel ?? 'info'),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
static init(opts) {
|
|
31
|
+
const cfg = (0, config_1.loadConfig)({ projectRoot: '.', environment: process.env.NODE_ENV });
|
|
32
|
+
const merged = {
|
|
33
|
+
applicationId: cfg.drtrace.applicationId,
|
|
34
|
+
daemonUrl: cfg.drtrace.daemonUrl || 'http://localhost:8001',
|
|
35
|
+
enabled: cfg.drtrace.enabled ?? true,
|
|
36
|
+
logLevel: (cfg.drtrace.logLevel ?? 'info'),
|
|
37
|
+
batchSize: cfg.drtrace.batchSize ?? 50,
|
|
38
|
+
flushIntervalMs: cfg.drtrace.flushIntervalMs ?? 1000,
|
|
39
|
+
...opts,
|
|
40
|
+
};
|
|
41
|
+
return new DrTrace(merged);
|
|
42
|
+
}
|
|
43
|
+
attachToConsole() {
|
|
44
|
+
if (!this.enabled)
|
|
45
|
+
return;
|
|
46
|
+
this.logger.attachToConsole();
|
|
47
|
+
}
|
|
48
|
+
detachFromConsole() {
|
|
49
|
+
this.logger.detachFromConsole();
|
|
50
|
+
}
|
|
51
|
+
log(message, level = 'info', context) {
|
|
52
|
+
if (!this.enabled)
|
|
53
|
+
return;
|
|
54
|
+
this.logger.log(level, message, context);
|
|
55
|
+
}
|
|
56
|
+
error(message, context) {
|
|
57
|
+
if (!this.enabled)
|
|
58
|
+
return;
|
|
59
|
+
this.logger.log('error', message, context);
|
|
60
|
+
}
|
|
61
|
+
async shutdown() {
|
|
62
|
+
await this.queue.flush();
|
|
63
|
+
this.queue.stop();
|
|
64
|
+
this.detachFromConsole();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.DrTrace = DrTrace;
|
|
@@ -288,6 +288,78 @@ def interact_with_daemon(query: str) -> str:
|
|
|
288
288
|
|
|
289
289
|
---
|
|
290
290
|
|
|
291
|
+
## Important: Timestamps Are UTC
|
|
292
|
+
|
|
293
|
+
All timestamps in DrTrace API are **UTC Unix timestamps**:
|
|
294
|
+
|
|
295
|
+
| Field/Param | Format | Timezone |
|
|
296
|
+
|-------------|--------|----------|
|
|
297
|
+
| `ts` (in logs) | Unix float | UTC |
|
|
298
|
+
| `start_ts`, `end_ts` | Unix float | UTC |
|
|
299
|
+
| `since`, `until` | Relative or ISO 8601 | UTC |
|
|
300
|
+
|
|
301
|
+
**Key Rules**:
|
|
302
|
+
- ISO 8601 without timezone (e.g., `2025-12-31T02:44:03`) is interpreted as **UTC**, not local time
|
|
303
|
+
- Relative times (`5m`, `1h`) are relative to server's current UTC time
|
|
304
|
+
- To query with local time, include timezone offset: `2025-12-31T09:44:03+07:00`
|
|
305
|
+
|
|
306
|
+
### Converting Local Time to UTC
|
|
307
|
+
|
|
308
|
+
**Python:**
|
|
309
|
+
```python
|
|
310
|
+
from datetime import datetime, timezone, timedelta
|
|
311
|
+
|
|
312
|
+
# Local time (e.g., 2025-12-31 09:44:03 in GMT+7)
|
|
313
|
+
local_time = datetime(2025, 12, 31, 9, 44, 3)
|
|
314
|
+
|
|
315
|
+
# Method 1: If you know your timezone offset
|
|
316
|
+
local_tz = timezone(timedelta(hours=7)) # GMT+7
|
|
317
|
+
local_aware = local_time.replace(tzinfo=local_tz)
|
|
318
|
+
utc_time = local_aware.astimezone(timezone.utc)
|
|
319
|
+
unix_ts = utc_time.timestamp()
|
|
320
|
+
print(f"UTC Unix timestamp: {unix_ts}")
|
|
321
|
+
|
|
322
|
+
# Method 2: Using system timezone
|
|
323
|
+
import time
|
|
324
|
+
unix_ts = time.mktime(local_time.timetuple())
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Bash:**
|
|
328
|
+
```bash
|
|
329
|
+
# Convert local time to Unix timestamp
|
|
330
|
+
date -d "2025-12-31 09:44:03" +%s
|
|
331
|
+
|
|
332
|
+
# Convert with explicit timezone
|
|
333
|
+
TZ=UTC date -d "2025-12-31T02:44:03" +%s
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### API Query Examples with Timezone
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Option 1: Include timezone in ISO 8601 (recommended for local time)
|
|
340
|
+
curl "http://localhost:8001/logs/query?since=2025-12-31T09:44:03%2B07:00"
|
|
341
|
+
|
|
342
|
+
# Option 2: Use relative time (always relative to server UTC time)
|
|
343
|
+
curl "http://localhost:8001/logs/query?since=5m"
|
|
344
|
+
|
|
345
|
+
# Option 3: Convert to UTC Unix timestamp first
|
|
346
|
+
UTC_TS=$(TZ=UTC date -d "2025-12-31T02:44:03" +%s)
|
|
347
|
+
curl "http://localhost:8001/logs/query?start_ts=$UTC_TS"
|
|
348
|
+
|
|
349
|
+
# Option 4: Use ISO 8601 in UTC (note: no timezone = UTC)
|
|
350
|
+
curl "http://localhost:8001/logs/query?since=2025-12-31T02:44:03"
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Common Timezone Pitfalls
|
|
354
|
+
|
|
355
|
+
1. **ISO 8601 Without Timezone**: Interpreted as UTC, not local time. If you pass `2025-12-31T09:44:03` thinking it's local 9:44 AM, it will be treated as 9:44 AM UTC.
|
|
356
|
+
|
|
357
|
+
2. **Server vs Client Timezone**: If your server is in a different timezone than your client, always use explicit UTC timestamps or include timezone offsets.
|
|
358
|
+
|
|
359
|
+
3. **Relative Times**: `since=5m` means 5 minutes before server's current UTC time, regardless of your local timezone.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
291
363
|
## Related Documentation
|
|
292
364
|
|
|
293
365
|
- `docs/daemon-interaction-guide.md` - OpenAPI discovery details
|
|
@@ -295,4 +367,4 @@ def interact_with_daemon(query: str) -> str:
|
|
|
295
367
|
|
|
296
368
|
---
|
|
297
369
|
|
|
298
|
-
**Last Updated**: 2025-12-
|
|
370
|
+
**Last Updated**: 2025-12-31
|
|
@@ -11,24 +11,25 @@ You must fully embody this agent's persona and follow all activation instruction
|
|
|
11
11
|
<step n="1">Load persona from this current agent file (already in context)</step>
|
|
12
12
|
<step n="2">Remember: You are a Log Analysis Specialist</step>
|
|
13
13
|
<step n="3">READ the entire story file BEFORE any analysis - understand the query parsing rules</step>
|
|
14
|
-
<step n="4">When processing a user query, try methods in this order:
|
|
15
|
-
|
|
16
|
-
**Method 1 (Preferred)**:
|
|
14
|
+
<step n="4">When processing a user query, try methods in this order (see `agents/daemon-method-selection.md` for details):
|
|
15
|
+
|
|
16
|
+
**Method 1 (Preferred)**: HTTP/curl
|
|
17
|
+
- Simple, no Python dependencies, works in any environment
|
|
18
|
+
- Check status: `GET http://localhost:8001/status`
|
|
19
|
+
- Query logs: `GET http://localhost:8001/logs/query?since=5m&application_id=X`
|
|
20
|
+
- Analysis: `GET http://localhost:8001/analysis/why?application_id=X&since=5m`
|
|
21
|
+
- **CRITICAL**: First fetch `/openapi.json` to discover field names (e.g., timestamp is `ts`, NOT `timestamp`)
|
|
22
|
+
|
|
23
|
+
**Method 2 (Fallback)**: Python SDK
|
|
24
|
+
- Use when HTTP is blocked or you need async features
|
|
17
25
|
- Try: `from drtrace_service.agent_interface import process_agent_query, check_daemon_status`
|
|
18
|
-
-
|
|
26
|
+
- Use `response = await process_agent_query(user_query)` or `asyncio.run(process_agent_query(user_query))`
|
|
19
27
|
- Return the response string directly (it's already formatted markdown)
|
|
20
|
-
|
|
21
|
-
**Method 2 (Fallback)**: HTTP API
|
|
22
|
-
- If Python import fails: Use HTTP requests to call DrTrace API endpoints
|
|
23
|
-
- **CRITICAL**: First fetch `/openapi.json` to discover field names (e.g., timestamp is `ts`, NOT `timestamp`)
|
|
24
|
-
- Check status: `GET http://localhost:8001/status`
|
|
25
|
-
- For analysis: `GET http://localhost:8001/analysis/why?application_id=X&start_ts=Y&end_ts=Z`
|
|
26
|
-
- Parse the JSON response using field names from OpenAPI schema
|
|
27
|
-
|
|
28
|
+
|
|
28
29
|
**Method 3 (Last resort)**: CLI commands
|
|
29
|
-
- If both
|
|
30
|
+
- If both HTTP and Python fail: Execute `python -m drtrace_service why --application-id X --since 5m`
|
|
30
31
|
- Parse the CLI output and format for the user
|
|
31
|
-
|
|
32
|
+
|
|
32
33
|
**Important**: Always check daemon status first. If daemon is unavailable, return clear error message with next steps.
|
|
33
34
|
</step>
|
|
34
35
|
<step n="5">If information is missing, ask the user for clarification with helpful suggestions</step>
|
|
@@ -11,7 +11,7 @@ You must fully embody this agent's persona and follow all activation instruction
|
|
|
11
11
|
<step n="1">Load persona from this current agent file (already in context)</step>
|
|
12
12
|
<step n="2">Remember: You are a Setup Guide Assistant for DrTrace</step>
|
|
13
13
|
<step n="3">Your primary mission is to walk users through DrTrace setup step-by-step using the help APIs and setup guide, not to guess or skip steps</step>
|
|
14
|
-
<step n="4">ALWAYS prefer Method 1 (
|
|
14
|
+
<step n="4">ALWAYS prefer Method 1 (HTTP/curl) → then Method 2 (Python SDK) → then Method 3 (CLI) in that exact order. See `agents/daemon-method-selection.md` for details.</step>
|
|
15
15
|
<step n="5">For each user interaction, clearly state the current step, what to do next, and how to verify it worked</step>
|
|
16
16
|
<step n="6">When calling help APIs, use:
|
|
17
17
|
- `start_setup_guide(language, project_root)` to begin or restart a guide
|
|
@@ -32,7 +32,7 @@ You must fully embody this agent's persona and follow all activation instruction
|
|
|
32
32
|
<r>NEVER skip verification or pretend steps are complete; use the setup guide and help APIs as the source of truth</r>
|
|
33
33
|
<r>ALWAYS explain what you are doing when progressing steps or troubleshooting issues</r>
|
|
34
34
|
<r>Display menu items exactly as defined in the menu section and in the order given</r>
|
|
35
|
-
<r>Prefer
|
|
35
|
+
<r>Prefer HTTP/curl, then Python SDK, then CLI in that order; explain fallbacks when switching methods</r>
|
|
36
36
|
</rules>
|
|
37
37
|
</activation>
|
|
38
38
|
|
package/dist/transport.js
CHANGED
|
@@ -15,7 +15,11 @@ class Transport {
|
|
|
15
15
|
if (events.length === 0)
|
|
16
16
|
return;
|
|
17
17
|
const url = `${this.daemonUrl}/logs/ingest`;
|
|
18
|
-
|
|
18
|
+
// Wrap batch with application_id at top level as required by daemon API
|
|
19
|
+
const payload = {
|
|
20
|
+
application_id: events[0].application_id,
|
|
21
|
+
logs: events,
|
|
22
|
+
};
|
|
19
23
|
const fetchImpl = globalThis.fetch;
|
|
20
24
|
if (!fetchImpl)
|
|
21
25
|
return; // Non-blocking skip
|
package/dist/types.d.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
2
2
|
export interface LogEvent {
|
|
3
|
-
|
|
4
|
-
applicationId: string;
|
|
3
|
+
ts: number;
|
|
5
4
|
level: LogLevel;
|
|
6
5
|
message: string;
|
|
6
|
+
application_id: string;
|
|
7
|
+
module_name: string;
|
|
7
8
|
context?: Record<string, unknown>;
|
|
8
9
|
}
|
|
10
|
+
export interface LogBatch {
|
|
11
|
+
application_id: string;
|
|
12
|
+
logs: LogEvent[];
|
|
13
|
+
}
|
|
9
14
|
export interface ClientOptions {
|
|
10
15
|
applicationId: string;
|
|
11
16
|
daemonUrl: string;
|
|
17
|
+
moduleName?: string;
|
|
12
18
|
enabled?: boolean;
|
|
13
19
|
logLevel?: LogLevel;
|
|
14
20
|
batchSize?: number;
|
package/package.json
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drtrace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "DrTrace JavaScript/TypeScript client",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"browser": "dist/browser.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
7
8
|
"exports": {
|
|
8
9
|
".": {
|
|
9
10
|
"types": "./dist/index.d.ts",
|
|
11
|
+
"browser": "./dist/browser.js",
|
|
12
|
+
"node": "./dist/index.js",
|
|
10
13
|
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./browser": {
|
|
16
|
+
"types": "./dist/browser.d.ts",
|
|
17
|
+
"default": "./dist/browser.js"
|
|
11
18
|
}
|
|
12
19
|
},
|
|
13
20
|
"bin": {
|
|
@@ -45,7 +52,10 @@
|
|
|
45
52
|
"error-tracking",
|
|
46
53
|
"debugging"
|
|
47
54
|
],
|
|
48
|
-
"author":
|
|
55
|
+
"author": {
|
|
56
|
+
"name": "Thanh Cao",
|
|
57
|
+
"email": "caoduythanhcantho@gmail.com"
|
|
58
|
+
},
|
|
49
59
|
"license": "MIT",
|
|
50
60
|
"files": [
|
|
51
61
|
"dist/",
|
|
@@ -55,7 +65,14 @@
|
|
|
55
65
|
],
|
|
56
66
|
"repository": {
|
|
57
67
|
"type": "git",
|
|
58
|
-
"url": "https://github.com/
|
|
68
|
+
"url": "git+https://github.com/CaoDuyThanh/drtrace.git",
|
|
59
69
|
"directory": "packages/javascript/drtrace-client"
|
|
70
|
+
},
|
|
71
|
+
"homepage": "https://github.com/CaoDuyThanh/drtrace#readme",
|
|
72
|
+
"bugs": {
|
|
73
|
+
"url": "https://github.com/CaoDuyThanh/drtrace/issues"
|
|
74
|
+
},
|
|
75
|
+
"engines": {
|
|
76
|
+
"node": ">=16.0.0"
|
|
60
77
|
}
|
|
61
78
|
}
|