devlogs-browser 1.1.1

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 ADDED
@@ -0,0 +1,48 @@
1
+ # devlogs-browser
2
+
3
+ Browser logging library for DevLogs - forwards console logs to OpenSearch.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install devlogs-browser
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```javascript
14
+ import * as devlogs from 'devlogs-browser';
15
+
16
+ devlogs.init({
17
+ url: 'http://admin:admin@localhost:9200',
18
+ index: 'devlogs-myapp',
19
+ area: 'frontend'
20
+ });
21
+
22
+ // Now console.log/warn/error/info are forwarded to OpenSearch
23
+ console.log('Hello from browser!');
24
+ ```
25
+
26
+ ## Production Deployment
27
+
28
+ Devlogs is a development tool and should not run in production:
29
+
30
+ ### Option 1: Conditional initialization
31
+
32
+ ```javascript
33
+ if (process.env.NODE_ENV === 'development') {
34
+ devlogs.init({ url: '...', index: '...' });
35
+ }
36
+ ```
37
+
38
+ ### Option 2: Don't import at all
39
+
40
+ Only import devlogs in development - bundlers will tree-shake it out of production builds.
41
+
42
+ ## API
43
+
44
+ - `init(options)` - Initialize and intercept console methods
45
+ - `destroy()` - Restore original console methods
46
+ - `setArea(area)` - Set the current area
47
+ - `setOperationId(id)` - Set the current operation ID
48
+ - `withOperation(fn, options)` - Run function with operation context
@@ -0,0 +1,22 @@
1
+ import type { DevlogsConfig, LogDocument } from './types';
2
+ /**
3
+ * Lightweight OpenSearch client for browser environments.
4
+ *
5
+ * Features:
6
+ * - Uses native fetch API (no dependencies)
7
+ * - Circuit breaker pattern: shows single error on connection failure
8
+ * - Fire-and-forget logging (non-blocking)
9
+ */
10
+ export declare class DevlogsOpenSearchClient {
11
+ private readonly baseUrl;
12
+ private readonly authHeader;
13
+ private readonly indexName;
14
+ private circuitOpen;
15
+ private errorShown;
16
+ constructor(config: DevlogsConfig);
17
+ /**
18
+ * Index a log document. Fire-and-forget - does not await response.
19
+ */
20
+ index(doc: LogDocument): void;
21
+ private handleConnectionError;
22
+ }
@@ -0,0 +1,305 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Parse a DEVLOGS URL into configuration components.
5
+ *
6
+ * Supports format: http://user:pass@host:port or https://user:pass@host:port
7
+ *
8
+ * Defaults:
9
+ * - scheme: http
10
+ * - host: localhost
11
+ * - port: 9200 for http, 443 for https
12
+ * - user: admin
13
+ * - password: admin
14
+ * - index: devlogs-0001
15
+ */
16
+ function parseDevlogsUrl(url, index) {
17
+ const parsed = new URL(url);
18
+ const scheme = parsed.protocol.replace(':', '');
19
+ return {
20
+ scheme,
21
+ host: parsed.hostname || 'localhost',
22
+ port: parsed.port
23
+ ? parseInt(parsed.port, 10)
24
+ : (scheme === 'https' ? 443 : 9200),
25
+ user: parsed.username || 'admin',
26
+ password: parsed.password || 'admin',
27
+ index: index || 'devlogs-0001',
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Python logging level numbers for compatibility
33
+ */
34
+ const LEVEL_MAP = {
35
+ debug: 10,
36
+ info: 20,
37
+ log: 20, // Treat console.log as INFO level
38
+ warn: 30,
39
+ error: 40,
40
+ };
41
+ /**
42
+ * Normalize console method name to standard log level
43
+ */
44
+ function normalizeLevel(method) {
45
+ if (method === 'warn')
46
+ return 'warning';
47
+ if (method === 'log')
48
+ return 'info';
49
+ return method;
50
+ }
51
+ /**
52
+ * Format console arguments into a single message string
53
+ */
54
+ function formatMessage(args) {
55
+ return args
56
+ .map((arg) => {
57
+ if (typeof arg === 'string') {
58
+ return arg;
59
+ }
60
+ if (arg instanceof Error) {
61
+ return `${arg.name}: ${arg.message}`;
62
+ }
63
+ try {
64
+ return JSON.stringify(arg);
65
+ }
66
+ catch {
67
+ return String(arg);
68
+ }
69
+ })
70
+ .join(' ');
71
+ }
72
+ /**
73
+ * Extract features from console arguments if an object is provided
74
+ */
75
+ function extractFeatures(args, contextFeatures) {
76
+ const features = {
77
+ userAgent: navigator.userAgent,
78
+ ...contextFeatures,
79
+ };
80
+ // If last argument is a plain object, merge it as features
81
+ const lastArg = args[args.length - 1];
82
+ if (lastArg &&
83
+ typeof lastArg === 'object' &&
84
+ !Array.isArray(lastArg) &&
85
+ !(lastArg instanceof Error)) {
86
+ Object.assign(features, lastArg);
87
+ }
88
+ return features;
89
+ }
90
+ /**
91
+ * Format a log entry into the devlogs document schema
92
+ */
93
+ function formatLogDocument(method, args, context) {
94
+ return {
95
+ doc_type: 'log_entry',
96
+ timestamp: new Date().toISOString(),
97
+ level: normalizeLevel(method),
98
+ levelno: LEVEL_MAP[method],
99
+ logger_name: context.loggerName,
100
+ message: formatMessage(args),
101
+ pathname: context.pathname,
102
+ lineno: null,
103
+ funcName: null,
104
+ area: context.area,
105
+ operation_id: context.operationId,
106
+ features: extractFeatures(args, context.features),
107
+ };
108
+ }
109
+
110
+ /**
111
+ * Store original console methods before interception.
112
+ * These are used for:
113
+ * 1. Calling the original console so browser devtools still work
114
+ * 2. Error reporting from the client without causing infinite loops
115
+ */
116
+ const originalConsole = {
117
+ log: console.log.bind(console),
118
+ warn: console.warn.bind(console),
119
+ error: console.error.bind(console),
120
+ debug: console.debug.bind(console),
121
+ info: console.info.bind(console),
122
+ };
123
+ const METHODS = ['log', 'warn', 'error', 'debug', 'info'];
124
+ /**
125
+ * Current logging context - shared across all console calls
126
+ */
127
+ let currentContext = {
128
+ area: null,
129
+ operationId: null,
130
+ loggerName: 'browser',
131
+ pathname: typeof window !== 'undefined' ? window.location.pathname : '/',
132
+ features: {},
133
+ };
134
+ /**
135
+ * Get the current logging context
136
+ */
137
+ function getContext() {
138
+ return { ...currentContext };
139
+ }
140
+ /**
141
+ * Update the logging context
142
+ */
143
+ function setContext(updates) {
144
+ currentContext = { ...currentContext, ...updates };
145
+ }
146
+ /**
147
+ * Set the application area
148
+ */
149
+ function setArea(area) {
150
+ currentContext.area = area;
151
+ }
152
+ /**
153
+ * Set the operation ID for correlation
154
+ */
155
+ function setOperationId(operationId) {
156
+ currentContext.operationId = operationId;
157
+ }
158
+ /**
159
+ * Set custom features to include in all logs
160
+ */
161
+ function setFeatures(features) {
162
+ currentContext.features = features;
163
+ }
164
+ /**
165
+ * Execute a function with a temporary operation ID
166
+ */
167
+ function withOperation(operationId, fn) {
168
+ const previousId = currentContext.operationId;
169
+ currentContext.operationId = operationId;
170
+ try {
171
+ return fn();
172
+ }
173
+ finally {
174
+ currentContext.operationId = previousId;
175
+ }
176
+ }
177
+ /**
178
+ * Intercept console methods to forward logs to the index.
179
+ * Original console methods are still called so devtools work normally.
180
+ */
181
+ function interceptConsole(client) {
182
+ METHODS.forEach((method) => {
183
+ console[method] = (...args) => {
184
+ // Always call the original console method first
185
+ originalConsole[method](...args);
186
+ // Format and send to index
187
+ const doc = formatLogDocument(method, args, getContext());
188
+ client.index(doc);
189
+ };
190
+ });
191
+ }
192
+ /**
193
+ * Restore original console methods
194
+ */
195
+ function restoreConsole() {
196
+ METHODS.forEach((method) => {
197
+ console[method] = originalConsole[method];
198
+ });
199
+ }
200
+
201
+ /**
202
+ * Lightweight OpenSearch client for browser environments.
203
+ *
204
+ * Features:
205
+ * - Uses native fetch API (no dependencies)
206
+ * - Circuit breaker pattern: shows single error on connection failure
207
+ * - Fire-and-forget logging (non-blocking)
208
+ */
209
+ class DevlogsOpenSearchClient {
210
+ constructor(config) {
211
+ this.circuitOpen = false;
212
+ this.errorShown = false;
213
+ this.baseUrl = `${config.scheme}://${config.host}:${config.port}`;
214
+ this.authHeader = `Basic ${btoa(`${config.user}:${config.password}`)}`;
215
+ this.indexName = config.index;
216
+ }
217
+ /**
218
+ * Index a log document. Fire-and-forget - does not await response.
219
+ */
220
+ index(doc) {
221
+ if (this.circuitOpen) {
222
+ return;
223
+ }
224
+ fetch(`${this.baseUrl}/${this.indexName}/_doc`, {
225
+ method: 'POST',
226
+ headers: {
227
+ 'Authorization': this.authHeader,
228
+ 'Content-Type': 'application/json',
229
+ },
230
+ body: JSON.stringify(doc),
231
+ }).catch((error) => {
232
+ this.handleConnectionError(error);
233
+ });
234
+ }
235
+ handleConnectionError(error) {
236
+ this.circuitOpen = true;
237
+ if (!this.errorShown) {
238
+ this.errorShown = true;
239
+ originalConsole.error('[devlogs] Unable to connect to index:', error);
240
+ }
241
+ }
242
+ }
243
+
244
+ let initialized = false;
245
+ let client = null;
246
+ /**
247
+ * Initialize the devlogs browser client.
248
+ *
249
+ * This intercepts console.log/warn/error/debug/info and forwards
250
+ * all log messages to the OpenSearch index.
251
+ *
252
+ * @example
253
+ * ```js
254
+ * devlogs.init({
255
+ * url: 'http://admin:admin@localhost:9200',
256
+ * area: 'frontend',
257
+ * loggerName: 'my-app'
258
+ * });
259
+ *
260
+ * console.log('App started'); // Forwarded to index
261
+ * ```
262
+ */
263
+ function init(options) {
264
+ if (initialized) {
265
+ originalConsole.warn('[devlogs] Already initialized');
266
+ return;
267
+ }
268
+ const config = parseDevlogsUrl(options.url, options.index);
269
+ client = new DevlogsOpenSearchClient(config);
270
+ setContext({
271
+ area: options.area || null,
272
+ operationId: options.operationId || null,
273
+ loggerName: options.loggerName || 'browser',
274
+ pathname: typeof window !== 'undefined' ? window.location.pathname : '/',
275
+ features: {},
276
+ });
277
+ interceptConsole(client);
278
+ initialized = true;
279
+ }
280
+ /**
281
+ * Disable devlogs and restore original console methods.
282
+ */
283
+ function destroy() {
284
+ if (!initialized) {
285
+ return;
286
+ }
287
+ restoreConsole();
288
+ client = null;
289
+ initialized = false;
290
+ }
291
+ /**
292
+ * Check if devlogs is currently initialized
293
+ */
294
+ function isInitialized() {
295
+ return initialized;
296
+ }
297
+
298
+ exports.destroy = destroy;
299
+ exports.init = init;
300
+ exports.isInitialized = isInitialized;
301
+ exports.setArea = setArea;
302
+ exports.setFeatures = setFeatures;
303
+ exports.setOperationId = setOperationId;
304
+ exports.withOperation = withOperation;
305
+ //# sourceMappingURL=devlogs.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devlogs.cjs.js","sources":["../src/url-parser.ts","../src/formatter.ts","../src/interceptor.ts","../src/client.ts","../src/index.ts"],"sourcesContent":[null,null,null,null,null],"names":[],"mappings":"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"}
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Parse a DEVLOGS URL into configuration components.
3
+ *
4
+ * Supports format: http://user:pass@host:port or https://user:pass@host:port
5
+ *
6
+ * Defaults:
7
+ * - scheme: http
8
+ * - host: localhost
9
+ * - port: 9200 for http, 443 for https
10
+ * - user: admin
11
+ * - password: admin
12
+ * - index: devlogs-0001
13
+ */
14
+ function parseDevlogsUrl(url, index) {
15
+ const parsed = new URL(url);
16
+ const scheme = parsed.protocol.replace(':', '');
17
+ return {
18
+ scheme,
19
+ host: parsed.hostname || 'localhost',
20
+ port: parsed.port
21
+ ? parseInt(parsed.port, 10)
22
+ : (scheme === 'https' ? 443 : 9200),
23
+ user: parsed.username || 'admin',
24
+ password: parsed.password || 'admin',
25
+ index: index || 'devlogs-0001',
26
+ };
27
+ }
28
+
29
+ /**
30
+ * Python logging level numbers for compatibility
31
+ */
32
+ const LEVEL_MAP = {
33
+ debug: 10,
34
+ info: 20,
35
+ log: 20, // Treat console.log as INFO level
36
+ warn: 30,
37
+ error: 40,
38
+ };
39
+ /**
40
+ * Normalize console method name to standard log level
41
+ */
42
+ function normalizeLevel(method) {
43
+ if (method === 'warn')
44
+ return 'warning';
45
+ if (method === 'log')
46
+ return 'info';
47
+ return method;
48
+ }
49
+ /**
50
+ * Format console arguments into a single message string
51
+ */
52
+ function formatMessage(args) {
53
+ return args
54
+ .map((arg) => {
55
+ if (typeof arg === 'string') {
56
+ return arg;
57
+ }
58
+ if (arg instanceof Error) {
59
+ return `${arg.name}: ${arg.message}`;
60
+ }
61
+ try {
62
+ return JSON.stringify(arg);
63
+ }
64
+ catch {
65
+ return String(arg);
66
+ }
67
+ })
68
+ .join(' ');
69
+ }
70
+ /**
71
+ * Extract features from console arguments if an object is provided
72
+ */
73
+ function extractFeatures(args, contextFeatures) {
74
+ const features = {
75
+ userAgent: navigator.userAgent,
76
+ ...contextFeatures,
77
+ };
78
+ // If last argument is a plain object, merge it as features
79
+ const lastArg = args[args.length - 1];
80
+ if (lastArg &&
81
+ typeof lastArg === 'object' &&
82
+ !Array.isArray(lastArg) &&
83
+ !(lastArg instanceof Error)) {
84
+ Object.assign(features, lastArg);
85
+ }
86
+ return features;
87
+ }
88
+ /**
89
+ * Format a log entry into the devlogs document schema
90
+ */
91
+ function formatLogDocument(method, args, context) {
92
+ return {
93
+ doc_type: 'log_entry',
94
+ timestamp: new Date().toISOString(),
95
+ level: normalizeLevel(method),
96
+ levelno: LEVEL_MAP[method],
97
+ logger_name: context.loggerName,
98
+ message: formatMessage(args),
99
+ pathname: context.pathname,
100
+ lineno: null,
101
+ funcName: null,
102
+ area: context.area,
103
+ operation_id: context.operationId,
104
+ features: extractFeatures(args, context.features),
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Store original console methods before interception.
110
+ * These are used for:
111
+ * 1. Calling the original console so browser devtools still work
112
+ * 2. Error reporting from the client without causing infinite loops
113
+ */
114
+ const originalConsole = {
115
+ log: console.log.bind(console),
116
+ warn: console.warn.bind(console),
117
+ error: console.error.bind(console),
118
+ debug: console.debug.bind(console),
119
+ info: console.info.bind(console),
120
+ };
121
+ const METHODS = ['log', 'warn', 'error', 'debug', 'info'];
122
+ /**
123
+ * Current logging context - shared across all console calls
124
+ */
125
+ let currentContext = {
126
+ area: null,
127
+ operationId: null,
128
+ loggerName: 'browser',
129
+ pathname: typeof window !== 'undefined' ? window.location.pathname : '/',
130
+ features: {},
131
+ };
132
+ /**
133
+ * Get the current logging context
134
+ */
135
+ function getContext() {
136
+ return { ...currentContext };
137
+ }
138
+ /**
139
+ * Update the logging context
140
+ */
141
+ function setContext(updates) {
142
+ currentContext = { ...currentContext, ...updates };
143
+ }
144
+ /**
145
+ * Set the application area
146
+ */
147
+ function setArea(area) {
148
+ currentContext.area = area;
149
+ }
150
+ /**
151
+ * Set the operation ID for correlation
152
+ */
153
+ function setOperationId(operationId) {
154
+ currentContext.operationId = operationId;
155
+ }
156
+ /**
157
+ * Set custom features to include in all logs
158
+ */
159
+ function setFeatures(features) {
160
+ currentContext.features = features;
161
+ }
162
+ /**
163
+ * Execute a function with a temporary operation ID
164
+ */
165
+ function withOperation(operationId, fn) {
166
+ const previousId = currentContext.operationId;
167
+ currentContext.operationId = operationId;
168
+ try {
169
+ return fn();
170
+ }
171
+ finally {
172
+ currentContext.operationId = previousId;
173
+ }
174
+ }
175
+ /**
176
+ * Intercept console methods to forward logs to the index.
177
+ * Original console methods are still called so devtools work normally.
178
+ */
179
+ function interceptConsole(client) {
180
+ METHODS.forEach((method) => {
181
+ console[method] = (...args) => {
182
+ // Always call the original console method first
183
+ originalConsole[method](...args);
184
+ // Format and send to index
185
+ const doc = formatLogDocument(method, args, getContext());
186
+ client.index(doc);
187
+ };
188
+ });
189
+ }
190
+ /**
191
+ * Restore original console methods
192
+ */
193
+ function restoreConsole() {
194
+ METHODS.forEach((method) => {
195
+ console[method] = originalConsole[method];
196
+ });
197
+ }
198
+
199
+ /**
200
+ * Lightweight OpenSearch client for browser environments.
201
+ *
202
+ * Features:
203
+ * - Uses native fetch API (no dependencies)
204
+ * - Circuit breaker pattern: shows single error on connection failure
205
+ * - Fire-and-forget logging (non-blocking)
206
+ */
207
+ class DevlogsOpenSearchClient {
208
+ constructor(config) {
209
+ this.circuitOpen = false;
210
+ this.errorShown = false;
211
+ this.baseUrl = `${config.scheme}://${config.host}:${config.port}`;
212
+ this.authHeader = `Basic ${btoa(`${config.user}:${config.password}`)}`;
213
+ this.indexName = config.index;
214
+ }
215
+ /**
216
+ * Index a log document. Fire-and-forget - does not await response.
217
+ */
218
+ index(doc) {
219
+ if (this.circuitOpen) {
220
+ return;
221
+ }
222
+ fetch(`${this.baseUrl}/${this.indexName}/_doc`, {
223
+ method: 'POST',
224
+ headers: {
225
+ 'Authorization': this.authHeader,
226
+ 'Content-Type': 'application/json',
227
+ },
228
+ body: JSON.stringify(doc),
229
+ }).catch((error) => {
230
+ this.handleConnectionError(error);
231
+ });
232
+ }
233
+ handleConnectionError(error) {
234
+ this.circuitOpen = true;
235
+ if (!this.errorShown) {
236
+ this.errorShown = true;
237
+ originalConsole.error('[devlogs] Unable to connect to index:', error);
238
+ }
239
+ }
240
+ }
241
+
242
+ let initialized = false;
243
+ let client = null;
244
+ /**
245
+ * Initialize the devlogs browser client.
246
+ *
247
+ * This intercepts console.log/warn/error/debug/info and forwards
248
+ * all log messages to the OpenSearch index.
249
+ *
250
+ * @example
251
+ * ```js
252
+ * devlogs.init({
253
+ * url: 'http://admin:admin@localhost:9200',
254
+ * area: 'frontend',
255
+ * loggerName: 'my-app'
256
+ * });
257
+ *
258
+ * console.log('App started'); // Forwarded to index
259
+ * ```
260
+ */
261
+ function init(options) {
262
+ if (initialized) {
263
+ originalConsole.warn('[devlogs] Already initialized');
264
+ return;
265
+ }
266
+ const config = parseDevlogsUrl(options.url, options.index);
267
+ client = new DevlogsOpenSearchClient(config);
268
+ setContext({
269
+ area: options.area || null,
270
+ operationId: options.operationId || null,
271
+ loggerName: options.loggerName || 'browser',
272
+ pathname: typeof window !== 'undefined' ? window.location.pathname : '/',
273
+ features: {},
274
+ });
275
+ interceptConsole(client);
276
+ initialized = true;
277
+ }
278
+ /**
279
+ * Disable devlogs and restore original console methods.
280
+ */
281
+ function destroy() {
282
+ if (!initialized) {
283
+ return;
284
+ }
285
+ restoreConsole();
286
+ client = null;
287
+ initialized = false;
288
+ }
289
+ /**
290
+ * Check if devlogs is currently initialized
291
+ */
292
+ function isInitialized() {
293
+ return initialized;
294
+ }
295
+
296
+ export { destroy, init, isInitialized, setArea, setFeatures, setOperationId, withOperation };
297
+ //# sourceMappingURL=devlogs.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devlogs.esm.js","sources":["../src/url-parser.ts","../src/formatter.ts","../src/interceptor.ts","../src/client.ts","../src/index.ts"],"sourcesContent":[null,null,null,null,null],"names":[],"mappings":"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"}
@@ -0,0 +1,310 @@
1
+ var devlogs = (function (exports) {
2
+ 'use strict';
3
+
4
+ /**
5
+ * Parse a DEVLOGS URL into configuration components.
6
+ *
7
+ * Supports format: http://user:pass@host:port or https://user:pass@host:port
8
+ *
9
+ * Defaults:
10
+ * - scheme: http
11
+ * - host: localhost
12
+ * - port: 9200 for http, 443 for https
13
+ * - user: admin
14
+ * - password: admin
15
+ * - index: devlogs-0001
16
+ */
17
+ function parseDevlogsUrl(url, index) {
18
+ const parsed = new URL(url);
19
+ const scheme = parsed.protocol.replace(':', '');
20
+ return {
21
+ scheme,
22
+ host: parsed.hostname || 'localhost',
23
+ port: parsed.port
24
+ ? parseInt(parsed.port, 10)
25
+ : (scheme === 'https' ? 443 : 9200),
26
+ user: parsed.username || 'admin',
27
+ password: parsed.password || 'admin',
28
+ index: index || 'devlogs-0001',
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Python logging level numbers for compatibility
34
+ */
35
+ const LEVEL_MAP = {
36
+ debug: 10,
37
+ info: 20,
38
+ log: 20, // Treat console.log as INFO level
39
+ warn: 30,
40
+ error: 40,
41
+ };
42
+ /**
43
+ * Normalize console method name to standard log level
44
+ */
45
+ function normalizeLevel(method) {
46
+ if (method === 'warn')
47
+ return 'warning';
48
+ if (method === 'log')
49
+ return 'info';
50
+ return method;
51
+ }
52
+ /**
53
+ * Format console arguments into a single message string
54
+ */
55
+ function formatMessage(args) {
56
+ return args
57
+ .map((arg) => {
58
+ if (typeof arg === 'string') {
59
+ return arg;
60
+ }
61
+ if (arg instanceof Error) {
62
+ return `${arg.name}: ${arg.message}`;
63
+ }
64
+ try {
65
+ return JSON.stringify(arg);
66
+ }
67
+ catch {
68
+ return String(arg);
69
+ }
70
+ })
71
+ .join(' ');
72
+ }
73
+ /**
74
+ * Extract features from console arguments if an object is provided
75
+ */
76
+ function extractFeatures(args, contextFeatures) {
77
+ const features = {
78
+ userAgent: navigator.userAgent,
79
+ ...contextFeatures,
80
+ };
81
+ // If last argument is a plain object, merge it as features
82
+ const lastArg = args[args.length - 1];
83
+ if (lastArg &&
84
+ typeof lastArg === 'object' &&
85
+ !Array.isArray(lastArg) &&
86
+ !(lastArg instanceof Error)) {
87
+ Object.assign(features, lastArg);
88
+ }
89
+ return features;
90
+ }
91
+ /**
92
+ * Format a log entry into the devlogs document schema
93
+ */
94
+ function formatLogDocument(method, args, context) {
95
+ return {
96
+ doc_type: 'log_entry',
97
+ timestamp: new Date().toISOString(),
98
+ level: normalizeLevel(method),
99
+ levelno: LEVEL_MAP[method],
100
+ logger_name: context.loggerName,
101
+ message: formatMessage(args),
102
+ pathname: context.pathname,
103
+ lineno: null,
104
+ funcName: null,
105
+ area: context.area,
106
+ operation_id: context.operationId,
107
+ features: extractFeatures(args, context.features),
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Store original console methods before interception.
113
+ * These are used for:
114
+ * 1. Calling the original console so browser devtools still work
115
+ * 2. Error reporting from the client without causing infinite loops
116
+ */
117
+ const originalConsole = {
118
+ log: console.log.bind(console),
119
+ warn: console.warn.bind(console),
120
+ error: console.error.bind(console),
121
+ debug: console.debug.bind(console),
122
+ info: console.info.bind(console),
123
+ };
124
+ const METHODS = ['log', 'warn', 'error', 'debug', 'info'];
125
+ /**
126
+ * Current logging context - shared across all console calls
127
+ */
128
+ let currentContext = {
129
+ area: null,
130
+ operationId: null,
131
+ loggerName: 'browser',
132
+ pathname: typeof window !== 'undefined' ? window.location.pathname : '/',
133
+ features: {},
134
+ };
135
+ /**
136
+ * Get the current logging context
137
+ */
138
+ function getContext() {
139
+ return { ...currentContext };
140
+ }
141
+ /**
142
+ * Update the logging context
143
+ */
144
+ function setContext(updates) {
145
+ currentContext = { ...currentContext, ...updates };
146
+ }
147
+ /**
148
+ * Set the application area
149
+ */
150
+ function setArea(area) {
151
+ currentContext.area = area;
152
+ }
153
+ /**
154
+ * Set the operation ID for correlation
155
+ */
156
+ function setOperationId(operationId) {
157
+ currentContext.operationId = operationId;
158
+ }
159
+ /**
160
+ * Set custom features to include in all logs
161
+ */
162
+ function setFeatures(features) {
163
+ currentContext.features = features;
164
+ }
165
+ /**
166
+ * Execute a function with a temporary operation ID
167
+ */
168
+ function withOperation(operationId, fn) {
169
+ const previousId = currentContext.operationId;
170
+ currentContext.operationId = operationId;
171
+ try {
172
+ return fn();
173
+ }
174
+ finally {
175
+ currentContext.operationId = previousId;
176
+ }
177
+ }
178
+ /**
179
+ * Intercept console methods to forward logs to the index.
180
+ * Original console methods are still called so devtools work normally.
181
+ */
182
+ function interceptConsole(client) {
183
+ METHODS.forEach((method) => {
184
+ console[method] = (...args) => {
185
+ // Always call the original console method first
186
+ originalConsole[method](...args);
187
+ // Format and send to index
188
+ const doc = formatLogDocument(method, args, getContext());
189
+ client.index(doc);
190
+ };
191
+ });
192
+ }
193
+ /**
194
+ * Restore original console methods
195
+ */
196
+ function restoreConsole() {
197
+ METHODS.forEach((method) => {
198
+ console[method] = originalConsole[method];
199
+ });
200
+ }
201
+
202
+ /**
203
+ * Lightweight OpenSearch client for browser environments.
204
+ *
205
+ * Features:
206
+ * - Uses native fetch API (no dependencies)
207
+ * - Circuit breaker pattern: shows single error on connection failure
208
+ * - Fire-and-forget logging (non-blocking)
209
+ */
210
+ class DevlogsOpenSearchClient {
211
+ constructor(config) {
212
+ this.circuitOpen = false;
213
+ this.errorShown = false;
214
+ this.baseUrl = `${config.scheme}://${config.host}:${config.port}`;
215
+ this.authHeader = `Basic ${btoa(`${config.user}:${config.password}`)}`;
216
+ this.indexName = config.index;
217
+ }
218
+ /**
219
+ * Index a log document. Fire-and-forget - does not await response.
220
+ */
221
+ index(doc) {
222
+ if (this.circuitOpen) {
223
+ return;
224
+ }
225
+ fetch(`${this.baseUrl}/${this.indexName}/_doc`, {
226
+ method: 'POST',
227
+ headers: {
228
+ 'Authorization': this.authHeader,
229
+ 'Content-Type': 'application/json',
230
+ },
231
+ body: JSON.stringify(doc),
232
+ }).catch((error) => {
233
+ this.handleConnectionError(error);
234
+ });
235
+ }
236
+ handleConnectionError(error) {
237
+ this.circuitOpen = true;
238
+ if (!this.errorShown) {
239
+ this.errorShown = true;
240
+ originalConsole.error('[devlogs] Unable to connect to index:', error);
241
+ }
242
+ }
243
+ }
244
+
245
+ let initialized = false;
246
+ let client = null;
247
+ /**
248
+ * Initialize the devlogs browser client.
249
+ *
250
+ * This intercepts console.log/warn/error/debug/info and forwards
251
+ * all log messages to the OpenSearch index.
252
+ *
253
+ * @example
254
+ * ```js
255
+ * devlogs.init({
256
+ * url: 'http://admin:admin@localhost:9200',
257
+ * area: 'frontend',
258
+ * loggerName: 'my-app'
259
+ * });
260
+ *
261
+ * console.log('App started'); // Forwarded to index
262
+ * ```
263
+ */
264
+ function init(options) {
265
+ if (initialized) {
266
+ originalConsole.warn('[devlogs] Already initialized');
267
+ return;
268
+ }
269
+ const config = parseDevlogsUrl(options.url, options.index);
270
+ client = new DevlogsOpenSearchClient(config);
271
+ setContext({
272
+ area: options.area || null,
273
+ operationId: options.operationId || null,
274
+ loggerName: options.loggerName || 'browser',
275
+ pathname: typeof window !== 'undefined' ? window.location.pathname : '/',
276
+ features: {},
277
+ });
278
+ interceptConsole(client);
279
+ initialized = true;
280
+ }
281
+ /**
282
+ * Disable devlogs and restore original console methods.
283
+ */
284
+ function destroy() {
285
+ if (!initialized) {
286
+ return;
287
+ }
288
+ restoreConsole();
289
+ client = null;
290
+ initialized = false;
291
+ }
292
+ /**
293
+ * Check if devlogs is currently initialized
294
+ */
295
+ function isInitialized() {
296
+ return initialized;
297
+ }
298
+
299
+ exports.destroy = destroy;
300
+ exports.init = init;
301
+ exports.isInitialized = isInitialized;
302
+ exports.setArea = setArea;
303
+ exports.setFeatures = setFeatures;
304
+ exports.setOperationId = setOperationId;
305
+ exports.withOperation = withOperation;
306
+
307
+ return exports;
308
+
309
+ })({});
310
+ //# sourceMappingURL=devlogs.iife.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devlogs.iife.js","sources":["../src/url-parser.ts","../src/formatter.ts","../src/interceptor.ts","../src/client.ts","../src/index.ts"],"sourcesContent":[null,null,null,null,null],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { LogContext, LogDocument, ConsoleMethod } from './types';
2
+ /**
3
+ * Format a log entry into the devlogs document schema
4
+ */
5
+ export declare function formatLogDocument(method: ConsoleMethod, args: unknown[], context: LogContext): LogDocument;
@@ -0,0 +1,30 @@
1
+ import type { DevlogsOptions } from './types';
2
+ import { setArea, setOperationId, setFeatures, withOperation } from './interceptor';
3
+ /**
4
+ * Initialize the devlogs browser client.
5
+ *
6
+ * This intercepts console.log/warn/error/debug/info and forwards
7
+ * all log messages to the OpenSearch index.
8
+ *
9
+ * @example
10
+ * ```js
11
+ * devlogs.init({
12
+ * url: 'http://admin:admin@localhost:9200',
13
+ * area: 'frontend',
14
+ * loggerName: 'my-app'
15
+ * });
16
+ *
17
+ * console.log('App started'); // Forwarded to index
18
+ * ```
19
+ */
20
+ export declare function init(options: DevlogsOptions): void;
21
+ /**
22
+ * Disable devlogs and restore original console methods.
23
+ */
24
+ export declare function destroy(): void;
25
+ /**
26
+ * Check if devlogs is currently initialized
27
+ */
28
+ export declare function isInitialized(): boolean;
29
+ export { setArea, setOperationId, setFeatures, withOperation };
30
+ export type { DevlogsOptions, LogContext, LogDocument } from './types';
@@ -0,0 +1,42 @@
1
+ import type { LogContext, OriginalConsole } from './types';
2
+ import type { DevlogsOpenSearchClient } from './client';
3
+ /**
4
+ * Store original console methods before interception.
5
+ * These are used for:
6
+ * 1. Calling the original console so browser devtools still work
7
+ * 2. Error reporting from the client without causing infinite loops
8
+ */
9
+ export declare const originalConsole: OriginalConsole;
10
+ /**
11
+ * Get the current logging context
12
+ */
13
+ export declare function getContext(): LogContext;
14
+ /**
15
+ * Update the logging context
16
+ */
17
+ export declare function setContext(updates: Partial<LogContext>): void;
18
+ /**
19
+ * Set the application area
20
+ */
21
+ export declare function setArea(area: string | null): void;
22
+ /**
23
+ * Set the operation ID for correlation
24
+ */
25
+ export declare function setOperationId(operationId: string | null): void;
26
+ /**
27
+ * Set custom features to include in all logs
28
+ */
29
+ export declare function setFeatures(features: Record<string, unknown>): void;
30
+ /**
31
+ * Execute a function with a temporary operation ID
32
+ */
33
+ export declare function withOperation<T>(operationId: string, fn: () => T): T;
34
+ /**
35
+ * Intercept console methods to forward logs to the index.
36
+ * Original console methods are still called so devtools work normally.
37
+ */
38
+ export declare function interceptConsole(client: DevlogsOpenSearchClient): void;
39
+ /**
40
+ * Restore original console methods
41
+ */
42
+ export declare function restoreConsole(): void;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Configuration parsed from the DEVLOGS URL
3
+ */
4
+ export interface DevlogsConfig {
5
+ scheme: 'http' | 'https';
6
+ host: string;
7
+ port: number;
8
+ user: string;
9
+ password: string;
10
+ index: string;
11
+ }
12
+ /**
13
+ * Options for initializing the devlogs client
14
+ */
15
+ export interface DevlogsOptions {
16
+ /** OpenSearch URL in format: http://user:pass@host:port */
17
+ url: string;
18
+ /** Index name (default: devlogs-0001) */
19
+ index?: string;
20
+ /** Application area/subsystem identifier */
21
+ area?: string;
22
+ /** Operation ID for log correlation */
23
+ operationId?: string;
24
+ /** Logger name (default: browser) */
25
+ loggerName?: string;
26
+ }
27
+ /**
28
+ * Current logging context
29
+ */
30
+ export interface LogContext {
31
+ area: string | null;
32
+ operationId: string | null;
33
+ loggerName: string;
34
+ pathname: string;
35
+ features: Record<string, unknown>;
36
+ }
37
+ /**
38
+ * Log document matching the devlogs schema
39
+ */
40
+ export interface LogDocument {
41
+ doc_type: 'log_entry';
42
+ timestamp: string;
43
+ level: string;
44
+ levelno: number;
45
+ logger_name: string;
46
+ message: string;
47
+ pathname: string;
48
+ lineno: number | null;
49
+ funcName: string | null;
50
+ area: string | null;
51
+ operation_id: string | null;
52
+ features: Record<string, unknown>;
53
+ }
54
+ /**
55
+ * Console method names that we intercept
56
+ */
57
+ export type ConsoleMethod = 'log' | 'warn' | 'error' | 'debug' | 'info';
58
+ /**
59
+ * Mapping of console methods to their original implementations
60
+ */
61
+ export type OriginalConsole = {
62
+ [K in ConsoleMethod]: (...args: unknown[]) => void;
63
+ };
@@ -0,0 +1,15 @@
1
+ import type { DevlogsConfig } from './types';
2
+ /**
3
+ * Parse a DEVLOGS URL into configuration components.
4
+ *
5
+ * Supports format: http://user:pass@host:port or https://user:pass@host:port
6
+ *
7
+ * Defaults:
8
+ * - scheme: http
9
+ * - host: localhost
10
+ * - port: 9200 for http, 443 for https
11
+ * - user: admin
12
+ * - password: admin
13
+ * - index: devlogs-0001
14
+ */
15
+ export declare function parseDevlogsUrl(url: string, index?: string): DevlogsConfig;
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "devlogs-browser",
3
+ "version": "1.1.1",
4
+ "type": "module",
5
+ "description": "Browser logging library for DevLogs - forwards console logs to OpenSearch",
6
+ "main": "dist/devlogs.cjs.js",
7
+ "module": "dist/devlogs.esm.js",
8
+ "browser": "dist/devlogs.iife.js",
9
+ "types": "dist/index.d.ts",
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "rollup -c",
15
+ "dev": "rollup -c -w",
16
+ "typecheck": "tsc --noEmit"
17
+ },
18
+ "devDependencies": {
19
+ "@rollup/plugin-typescript": "^11.1.6",
20
+ "rollup": "^4.9.0",
21
+ "tslib": "^2.6.2",
22
+ "typescript": "^5.3.0"
23
+ },
24
+ "keywords": [
25
+ "logging",
26
+ "devlogs",
27
+ "opensearch",
28
+ "browser",
29
+ "console"
30
+ ],
31
+ "license": "MIT"
32
+ }