@echoteam/signoz-react 1.0.7 → 1.2.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 +222 -7
- package/dist/index.d.ts +7 -0
- package/dist/index.esm.js +297 -7
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +297 -7
- package/dist/index.js.map +1 -1
- package/dist/types/tracing.d.ts +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,26 @@ Library React untuk monitoring dan tracing aplikasi menggunakan OpenTelemetry da
|
|
|
5
5
|
## 🚀 Fitur
|
|
6
6
|
|
|
7
7
|
- **Tracing Otomatis**: Integrasi OpenTelemetry untuk tracing HTTP requests, fetch, dan XMLHttpRequest
|
|
8
|
+
- **Request/Response Logging**: Otomatis melog data request dan response untuk debugging dan monitoring
|
|
9
|
+
- Log GET request dengan response data
|
|
10
|
+
- Log POST/PUT/PATCH request dengan request body dan response data
|
|
11
|
+
- **Log halaman frontend (page URL)** yang melakukan request
|
|
12
|
+
- Konfigurasi maksimal ukuran body yang di-log
|
|
13
|
+
- Data tersimpan di span attributes SignOz
|
|
14
|
+
- **Error Tracking**: Otomatis menangkap dan melog unhandled errors dan promise rejections
|
|
15
|
+
- Track JavaScript errors dengan stack trace
|
|
16
|
+
- Track unhandled promise rejections
|
|
17
|
+
- Error details tersimpan di SignOz untuk analisis
|
|
18
|
+
- **Navigation Tracking**: Track route changes dan page navigation
|
|
19
|
+
- Track initial page load
|
|
20
|
+
- Track SPA navigation (pushState/replaceState)
|
|
21
|
+
- Track browser back/forward (popstate)
|
|
22
|
+
- Navigation history tersimpan di SignOz
|
|
23
|
+
- **Document Load Performance**: Track page load performance metrics
|
|
24
|
+
- First Paint, First Contentful Paint
|
|
25
|
+
- DOM Content Loaded, Load Complete
|
|
26
|
+
- Resource timing
|
|
27
|
+
- **No Click Tracking**: User interaction (click events) tidak di-track untuk privacy dan performa
|
|
8
28
|
- **Error Boundary**: Komponen React untuk menangkap dan melaporkan error dengan tracing
|
|
9
29
|
- **Error Page**: Halaman error untuk React Router dengan integrasi tracing
|
|
10
30
|
- **TypeScript Support**: Dukungan penuh untuk TypeScript
|
|
@@ -39,14 +59,33 @@ REACT_APP_SIGNOZ_SERVICE_NAMESPACE=frontend
|
|
|
39
59
|
REACT_APP_SIGNOZ_URL=https://your-signoz-instance.com/v1/traces
|
|
40
60
|
REACT_APP_SIGNOZ_TRACE_SAMPLE_RATE=1.0
|
|
41
61
|
REACT_APP_SIGNOZ_ALLOWED_ORIGINS=https://api1.example.com,https://api2.example.com,/^https:\/\/.*\.your-domain\.com$/
|
|
62
|
+
|
|
63
|
+
# Konfigurasi Request/Response Logging (opsional)
|
|
64
|
+
REACT_APP_SIGNOZ_ENABLE_REQUEST_LOGGING=true
|
|
65
|
+
REACT_APP_SIGNOZ_LOG_REQUEST_BODY=true
|
|
66
|
+
REACT_APP_SIGNOZ_LOG_RESPONSE_BODY=true
|
|
67
|
+
REACT_APP_SIGNOZ_MAX_BODY_LOG_SIZE=10000
|
|
68
|
+
|
|
69
|
+
# Konfigurasi Tracking (opsional, default: true)
|
|
70
|
+
REACT_APP_SIGNOZ_ENABLE_DOCUMENT_LOAD=true
|
|
71
|
+
REACT_APP_SIGNOZ_ENABLE_ERROR_TRACKING=true
|
|
72
|
+
REACT_APP_SIGNOZ_ENABLE_NAVIGATION_TRACKING=true
|
|
42
73
|
```
|
|
43
74
|
|
|
44
75
|
> **Catatan untuk REACT_APP_SIGNOZ_ALLOWED_ORIGINS:**
|
|
45
76
|
> - Daftar URL yang diizinkan untuk CORS, dipisahkan dengan koma
|
|
46
77
|
> - Untuk RegExp pattern, gunakan format `/pattern/` (contoh: `/^https:\/\/.*\.example\.com$/`)
|
|
47
|
-
> -
|
|
78
|
+
> - Gunakan '*' untuk mengizinkan semua origin
|
|
79
|
+
> - Jika tidak diisi, default ke '*' (mengizinkan semua origin)
|
|
48
80
|
> - Spasi di sekitar koma akan dihapus otomatis
|
|
49
81
|
|
|
82
|
+
> **Catatan untuk Request/Response Logging:**
|
|
83
|
+
> - `REACT_APP_SIGNOZ_ENABLE_REQUEST_LOGGING`: Aktifkan/nonaktifkan logging request/response (default: true)
|
|
84
|
+
> - `REACT_APP_SIGNOZ_LOG_REQUEST_BODY`: Log body untuk POST/PUT/PATCH request (default: true)
|
|
85
|
+
> - `REACT_APP_SIGNOZ_LOG_RESPONSE_BODY`: Log response body untuk semua request (default: true)
|
|
86
|
+
> - `REACT_APP_SIGNOZ_MAX_BODY_LOG_SIZE`: Maksimal ukuran body yang di-log dalam bytes (default: 10000)
|
|
87
|
+
> - Data akan di-log ke console browser dan dikirim sebagai span attributes ke SignOz
|
|
88
|
+
|
|
50
89
|
### Inisialisasi
|
|
51
90
|
|
|
52
91
|
```typescript
|
|
@@ -83,13 +122,182 @@ initializeSignOzTracing({
|
|
|
83
122
|
},
|
|
84
123
|
allowedOrigins: [
|
|
85
124
|
'https://api.example.com',
|
|
86
|
-
/^https:\/\/.*\.your-domain\.com
|
|
87
|
-
|
|
125
|
+
/^https:\/\/.*\.your-domain\.com$/,
|
|
126
|
+
'*' // Mengizinkan semua origin (default)
|
|
127
|
+
],
|
|
128
|
+
// Konfigurasi logging request/response
|
|
129
|
+
enableRequestLogging: true, // Aktifkan logging (default: true)
|
|
130
|
+
logRequestBody: true, // Log request body untuk POST/PUT/PATCH (default: true)
|
|
131
|
+
logResponseBody: true, // Log response body (default: true)
|
|
132
|
+
maxBodyLogSize: 10000, // Maksimal 10KB per log (default: 10000)
|
|
133
|
+
// Konfigurasi tracking
|
|
134
|
+
enableDocumentLoad: true, // Track page load performance (default: true)
|
|
135
|
+
enableErrorTracking: true, // Track unhandled errors (default: true)
|
|
136
|
+
enableNavigationTracking: true // Track route changes (default: true)
|
|
88
137
|
});
|
|
89
138
|
```
|
|
90
139
|
|
|
91
140
|
## 🎯 Penggunaan
|
|
92
141
|
|
|
142
|
+
### Request/Response Logging
|
|
143
|
+
|
|
144
|
+
Library ini secara otomatis melog semua HTTP request dan response yang dilakukan melalui `fetch` atau `XMLHttpRequest`. Data yang di-log meliputi:
|
|
145
|
+
|
|
146
|
+
**Untuk GET Request:**
|
|
147
|
+
- URL endpoint
|
|
148
|
+
- HTTP method
|
|
149
|
+
- Status code response
|
|
150
|
+
- Response body (jika `logResponseBody: true`)
|
|
151
|
+
- **URL halaman frontend** yang melakukan request (page.url, page.pathname)
|
|
152
|
+
|
|
153
|
+
**Untuk POST/PUT/PATCH Request:**
|
|
154
|
+
- URL endpoint
|
|
155
|
+
- HTTP method
|
|
156
|
+
- Request body (jika `logRequestBody: true`)
|
|
157
|
+
- Status code response
|
|
158
|
+
- Response body (jika `logResponseBody: true`)
|
|
159
|
+
- **URL halaman frontend** yang melakukan request (page.url, page.pathname)
|
|
160
|
+
|
|
161
|
+
**Contoh Output di Console:**
|
|
162
|
+
```
|
|
163
|
+
[SignOz] GET Response from https://api.example.com/users (200) on page /dashboard: {"users":[{"id":1,"name":"John"}]}
|
|
164
|
+
[SignOz] POST Request to https://api.example.com/users from page /users/create: {"name":"Jane","email":"jane@example.com"}
|
|
165
|
+
[SignOz] POST Response from https://api.example.com/users (201) on page /users/create: {"id":2,"name":"Jane","email":"jane@example.com"}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Melihat Data di SignOz Dashboard:**
|
|
169
|
+
1. Buka SignOz dashboard
|
|
170
|
+
2. Navigasi ke **Traces**
|
|
171
|
+
3. Pilih trace yang ingin dilihat
|
|
172
|
+
4. Lihat span attributes:
|
|
173
|
+
- `http.request.body`: Body dari request (untuk POST/PUT/PATCH)
|
|
174
|
+
- `http.response.body`: Body dari response
|
|
175
|
+
- `http.url`: URL endpoint
|
|
176
|
+
- `http.method`: HTTP method
|
|
177
|
+
- `http.status_code`: Status code response
|
|
178
|
+
- `page.url`: URL halaman frontend yang melakukan request
|
|
179
|
+
- `page.pathname`: Pathname halaman frontend
|
|
180
|
+
- `page.search`: Query parameters halaman frontend
|
|
181
|
+
- `page.hash`: Hash fragment halaman frontend
|
|
182
|
+
|
|
183
|
+
**Menonaktifkan Logging:**
|
|
184
|
+
```typescript
|
|
185
|
+
// Nonaktifkan semua logging
|
|
186
|
+
initializeSignOzTracing({
|
|
187
|
+
// ... konfigurasi lainnya
|
|
188
|
+
enableRequestLogging: false
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Atau hanya nonaktifkan logging body tertentu
|
|
192
|
+
initializeSignOzTracing({
|
|
193
|
+
// ... konfigurasi lainnya
|
|
194
|
+
enableRequestLogging: true,
|
|
195
|
+
logRequestBody: false, // Tidak log request body
|
|
196
|
+
logResponseBody: true // Tetap log response body
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Error Tracking
|
|
201
|
+
|
|
202
|
+
Library ini otomatis menangkap dan melog semua unhandled errors dan promise rejections.
|
|
203
|
+
|
|
204
|
+
**Contoh Output di Console:**
|
|
205
|
+
```
|
|
206
|
+
[SignOz] Unhandled Error: {
|
|
207
|
+
message: "Cannot read property 'foo' of undefined",
|
|
208
|
+
filename: "app.js",
|
|
209
|
+
lineno: 42,
|
|
210
|
+
colno: 15,
|
|
211
|
+
stack: "TypeError: Cannot read property 'foo' of undefined\n at App.js:42:15"
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
[SignOz] Unhandled Promise Rejection: Error: API call failed
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Data yang Di-track:**
|
|
218
|
+
- Error message
|
|
219
|
+
- Stack trace
|
|
220
|
+
- Filename dan line number
|
|
221
|
+
- Error type (unhandled error atau promise rejection)
|
|
222
|
+
|
|
223
|
+
**Melihat di SignOz:**
|
|
224
|
+
1. Navigasi ke **Traces**
|
|
225
|
+
2. Filter by span name: "Unhandled Error" atau "Unhandled Promise Rejection"
|
|
226
|
+
3. Lihat span attributes:
|
|
227
|
+
- `error.type`: Tipe error
|
|
228
|
+
- `error.message`: Pesan error
|
|
229
|
+
- `error.stack`: Stack trace
|
|
230
|
+
- `error.filename`: File yang error
|
|
231
|
+
- `error.lineno`: Line number
|
|
232
|
+
|
|
233
|
+
**Menonaktifkan Error Tracking:**
|
|
234
|
+
```typescript
|
|
235
|
+
initializeSignOzTracing({
|
|
236
|
+
// ... konfigurasi lainnya
|
|
237
|
+
enableErrorTracking: false
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Navigation Tracking
|
|
242
|
+
|
|
243
|
+
Library ini otomatis track semua route changes dan page navigation.
|
|
244
|
+
|
|
245
|
+
**Contoh Output di Console:**
|
|
246
|
+
```
|
|
247
|
+
[SignOz] Page Load: { url: "https://example.com/", pathname: "/" }
|
|
248
|
+
[SignOz] Navigation (pushState): { from: "/", to: "/users", pathname: "/users" }
|
|
249
|
+
[SignOz] Navigation (popstate): { from: "/users", to: "/", pathname: "/" }
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Data yang Di-track:**
|
|
253
|
+
- Initial page load
|
|
254
|
+
- SPA navigation (React Router, etc)
|
|
255
|
+
- Browser back/forward navigation
|
|
256
|
+
- URL, pathname, search params, hash
|
|
257
|
+
|
|
258
|
+
**Melihat di SignOz:**
|
|
259
|
+
1. Navigasi ke **Traces**
|
|
260
|
+
2. Filter by span name: "Page Load" atau "Navigation"
|
|
261
|
+
3. Lihat span attributes:
|
|
262
|
+
- `navigation.type`: Tipe navigasi (initial, pushState, replaceState, popstate)
|
|
263
|
+
- `navigation.from`: URL sebelumnya
|
|
264
|
+
- `navigation.to`: URL tujuan
|
|
265
|
+
- `navigation.pathname`: Pathname
|
|
266
|
+
- `navigation.search`: Query parameters
|
|
267
|
+
- `navigation.hash`: Hash fragment
|
|
268
|
+
|
|
269
|
+
**Menonaktifkan Navigation Tracking:**
|
|
270
|
+
```typescript
|
|
271
|
+
initializeSignOzTracing({
|
|
272
|
+
// ... konfigurasi lainnya
|
|
273
|
+
enableNavigationTracking: false
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Document Load Performance
|
|
278
|
+
|
|
279
|
+
Library ini otomatis track page load performance metrics menggunakan Navigation Timing API.
|
|
280
|
+
|
|
281
|
+
**Metrics yang Di-track:**
|
|
282
|
+
- First Paint (FP)
|
|
283
|
+
- First Contentful Paint (FCP)
|
|
284
|
+
- DOM Content Loaded
|
|
285
|
+
- Load Complete
|
|
286
|
+
- Resource timing (CSS, JS, images, etc)
|
|
287
|
+
|
|
288
|
+
**Melihat di SignOz:**
|
|
289
|
+
1. Navigasi ke **Traces**
|
|
290
|
+
2. Filter by span name: "documentLoad" atau "documentFetch"
|
|
291
|
+
3. Lihat metrics untuk page load performance
|
|
292
|
+
|
|
293
|
+
**Menonaktifkan Document Load Tracking:**
|
|
294
|
+
```typescript
|
|
295
|
+
initializeSignOzTracing({
|
|
296
|
+
// ... konfigurasi lainnya
|
|
297
|
+
enableDocumentLoad: false
|
|
298
|
+
});
|
|
299
|
+
```
|
|
300
|
+
|
|
93
301
|
### Error Boundary
|
|
94
302
|
|
|
95
303
|
#### Penggunaan Dasar
|
|
@@ -110,9 +318,9 @@ function App() {
|
|
|
110
318
|
import { ErrorBoundary, ErrorBoundaryProps } from '@echoteam/signoz-react';
|
|
111
319
|
|
|
112
320
|
// Custom fallback component
|
|
113
|
-
const CustomErrorFallback: React.FC<{ error: Error; resetErrorBoundary: () => void }> = ({
|
|
114
|
-
error,
|
|
115
|
-
resetErrorBoundary
|
|
321
|
+
const CustomErrorFallback: React.FC<{ error: Error; resetErrorBoundary: () => void }> = ({
|
|
322
|
+
error,
|
|
323
|
+
resetErrorBoundary
|
|
116
324
|
}) => (
|
|
117
325
|
<div className="custom-error">
|
|
118
326
|
<h2>Terjadi Kesalahan!</h2>
|
|
@@ -239,7 +447,14 @@ Inisialisasi SignOz tracing untuk aplikasi React.
|
|
|
239
447
|
- `maxQueueSize`: Ukuran maksimum antrian span
|
|
240
448
|
- `scheduledDelayMillis`: Delay pengiriman batch dalam milidetik
|
|
241
449
|
- `exportTimeoutMillis`: Timeout ekspor dalam milidetik
|
|
242
|
-
- `allowedOrigins` (
|
|
450
|
+
- `allowedOrigins` (wajib): Array URL/RegExp yang diizinkan untuk CORS. Gunakan ['*'] untuk mengizinkan semua origin
|
|
451
|
+
- `enableRequestLogging` (opsional): Aktifkan logging request/response (default: true)
|
|
452
|
+
- `logRequestBody` (opsional): Log request body untuk POST/PUT/PATCH (default: true)
|
|
453
|
+
- `logResponseBody` (opsional): Log response body untuk semua request (default: true)
|
|
454
|
+
- `maxBodyLogSize` (opsional): Maksimal ukuran body yang di-log dalam bytes (default: 10000)
|
|
455
|
+
- `enableDocumentLoad` (opsional): Aktifkan document load instrumentation (default: true)
|
|
456
|
+
- `enableErrorTracking` (opsional): Aktifkan automatic error tracking (default: true)
|
|
457
|
+
- `enableNavigationTracking` (opsional): Aktifkan navigation/route tracking (default: true)
|
|
243
458
|
|
|
244
459
|
### `ErrorBoundary`
|
|
245
460
|
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,13 @@ interface SignOzConfig {
|
|
|
13
13
|
exportTimeoutMillis?: number;
|
|
14
14
|
};
|
|
15
15
|
allowedOrigins?: (string | RegExp)[];
|
|
16
|
+
enableRequestLogging?: boolean;
|
|
17
|
+
logRequestBody?: boolean;
|
|
18
|
+
logResponseBody?: boolean;
|
|
19
|
+
maxBodyLogSize?: number;
|
|
20
|
+
enableDocumentLoad?: boolean;
|
|
21
|
+
enableErrorTracking?: boolean;
|
|
22
|
+
enableNavigationTracking?: boolean;
|
|
16
23
|
}
|
|
17
24
|
declare global {
|
|
18
25
|
interface Window {
|
package/dist/index.esm.js
CHANGED
|
@@ -15263,17 +15263,13 @@ function getConfigValue(key) {
|
|
|
15263
15263
|
}
|
|
15264
15264
|
// Fungsi untuk memvalidasi konfigurasi
|
|
15265
15265
|
function validateConfig(config) {
|
|
15266
|
-
const requiredFields = ['serviceName', 'serviceVersion', 'environment', 'serviceNamespace', 'url'
|
|
15266
|
+
const requiredFields = ['serviceName', 'serviceVersion', 'environment', 'serviceNamespace', 'url'];
|
|
15267
15267
|
const missingFields = [];
|
|
15268
15268
|
for (const field of requiredFields) {
|
|
15269
15269
|
if (!config[field]) {
|
|
15270
15270
|
missingFields.push(field);
|
|
15271
15271
|
}
|
|
15272
15272
|
}
|
|
15273
|
-
// Khusus validasi allowedOrigins: pastikan array tidak kosong
|
|
15274
|
-
if (config.allowedOrigins && config.allowedOrigins.length === 0) {
|
|
15275
|
-
missingFields.push('allowedOrigins tidak boleh kosong demi keamanan CORS');
|
|
15276
|
-
}
|
|
15277
15273
|
return {
|
|
15278
15274
|
isValid: missingFields.length === 0,
|
|
15279
15275
|
missingFields
|
|
@@ -15297,6 +15293,255 @@ function parseAllowedOrigins(originsStr) {
|
|
|
15297
15293
|
return origin;
|
|
15298
15294
|
});
|
|
15299
15295
|
}
|
|
15296
|
+
// Fungsi helper untuk truncate body jika terlalu besar
|
|
15297
|
+
function truncateBody(body, maxSize) {
|
|
15298
|
+
try {
|
|
15299
|
+
const bodyStr = typeof body === 'string' ? body : JSON.stringify(body);
|
|
15300
|
+
if (bodyStr.length > maxSize) {
|
|
15301
|
+
return bodyStr.substring(0, maxSize) + '... [truncated]';
|
|
15302
|
+
}
|
|
15303
|
+
return bodyStr;
|
|
15304
|
+
}
|
|
15305
|
+
catch (e) {
|
|
15306
|
+
return '[Unable to serialize body]';
|
|
15307
|
+
}
|
|
15308
|
+
}
|
|
15309
|
+
// Fungsi untuk menambahkan logging ke fetch instrumentation
|
|
15310
|
+
function addFetchLogging(config) {
|
|
15311
|
+
if (!config.enableRequestLogging)
|
|
15312
|
+
return;
|
|
15313
|
+
const originalFetch = window.fetch;
|
|
15314
|
+
window.fetch = async function (...args) {
|
|
15315
|
+
const [resource, init] = args;
|
|
15316
|
+
const url = typeof resource === 'string' ? resource : (resource instanceof Request ? resource.url : resource.toString());
|
|
15317
|
+
const method = (init === null || init === void 0 ? void 0 : init.method) || 'GET';
|
|
15318
|
+
// Capture current page info
|
|
15319
|
+
const pageUrl = window.location.href;
|
|
15320
|
+
const pagePath = window.location.pathname;
|
|
15321
|
+
const tracer = trace.getTracer('fetch-logger');
|
|
15322
|
+
const span = tracer.startSpan(`HTTP ${method} ${url}`);
|
|
15323
|
+
try {
|
|
15324
|
+
// Log request data
|
|
15325
|
+
span.setAttribute('http.url', url);
|
|
15326
|
+
span.setAttribute('http.method', method);
|
|
15327
|
+
// Log page info (frontend URL)
|
|
15328
|
+
span.setAttribute('page.url', pageUrl);
|
|
15329
|
+
span.setAttribute('page.pathname', pagePath);
|
|
15330
|
+
span.setAttribute('page.search', window.location.search);
|
|
15331
|
+
span.setAttribute('page.hash', window.location.hash);
|
|
15332
|
+
if (config.logRequestBody && (init === null || init === void 0 ? void 0 : init.body) && ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase())) {
|
|
15333
|
+
const bodyStr = truncateBody(init.body, config.maxBodyLogSize);
|
|
15334
|
+
span.setAttribute('http.request.body', bodyStr);
|
|
15335
|
+
console.log(`[SignOz] ${method} Request to ${url} from page ${pagePath}:`, bodyStr);
|
|
15336
|
+
}
|
|
15337
|
+
const response = await originalFetch.apply(this, args);
|
|
15338
|
+
// Log response data
|
|
15339
|
+
span.setAttribute('http.status_code', response.status);
|
|
15340
|
+
if (config.logResponseBody && response.ok) {
|
|
15341
|
+
const clonedResponse = response.clone();
|
|
15342
|
+
try {
|
|
15343
|
+
const responseData = await clonedResponse.text();
|
|
15344
|
+
const truncatedData = truncateBody(responseData, config.maxBodyLogSize);
|
|
15345
|
+
span.setAttribute('http.response.body', truncatedData);
|
|
15346
|
+
console.log(`[SignOz] ${method} Response from ${url} (${response.status}) on page ${pagePath}:`, truncatedData);
|
|
15347
|
+
}
|
|
15348
|
+
catch (e) {
|
|
15349
|
+
console.warn('[SignOz] Failed to read response body:', e);
|
|
15350
|
+
}
|
|
15351
|
+
}
|
|
15352
|
+
else if (!response.ok) {
|
|
15353
|
+
console.log(`[SignOz] ${method} Request to ${url} from page ${pagePath} - Status: ${response.status}`);
|
|
15354
|
+
}
|
|
15355
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
15356
|
+
return response;
|
|
15357
|
+
}
|
|
15358
|
+
catch (error) {
|
|
15359
|
+
span.recordException(error);
|
|
15360
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
15361
|
+
console.error(`[SignOz] ${method} Error for ${url} on page ${pagePath}:`, error);
|
|
15362
|
+
throw error;
|
|
15363
|
+
}
|
|
15364
|
+
finally {
|
|
15365
|
+
span.end();
|
|
15366
|
+
}
|
|
15367
|
+
};
|
|
15368
|
+
}
|
|
15369
|
+
// Fungsi untuk menambahkan logging ke XMLHttpRequest instrumentation
|
|
15370
|
+
function addXHRLogging(config) {
|
|
15371
|
+
if (!config.enableRequestLogging)
|
|
15372
|
+
return;
|
|
15373
|
+
const OriginalXHR = window.XMLHttpRequest;
|
|
15374
|
+
window.XMLHttpRequest = function () {
|
|
15375
|
+
const xhr = new OriginalXHR();
|
|
15376
|
+
let method = '';
|
|
15377
|
+
let url = '';
|
|
15378
|
+
// Capture current page info when XHR is created
|
|
15379
|
+
const pageUrl = window.location.href;
|
|
15380
|
+
const pagePath = window.location.pathname;
|
|
15381
|
+
const originalOpen = xhr.open;
|
|
15382
|
+
xhr.open = function (...args) {
|
|
15383
|
+
method = args[0];
|
|
15384
|
+
url = args[1];
|
|
15385
|
+
return originalOpen.apply(this, args);
|
|
15386
|
+
};
|
|
15387
|
+
const originalSend = xhr.send;
|
|
15388
|
+
xhr.send = function (body) {
|
|
15389
|
+
const tracer = trace.getTracer('xhr-logger');
|
|
15390
|
+
const span = tracer.startSpan(`HTTP ${method} ${url}`);
|
|
15391
|
+
span.setAttribute('http.url', url);
|
|
15392
|
+
span.setAttribute('http.method', method);
|
|
15393
|
+
// Log page info (frontend URL)
|
|
15394
|
+
span.setAttribute('page.url', pageUrl);
|
|
15395
|
+
span.setAttribute('page.pathname', pagePath);
|
|
15396
|
+
span.setAttribute('page.search', window.location.search);
|
|
15397
|
+
span.setAttribute('page.hash', window.location.hash);
|
|
15398
|
+
// Log request body
|
|
15399
|
+
if (config.logRequestBody && body && ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase())) {
|
|
15400
|
+
const bodyStr = truncateBody(body, config.maxBodyLogSize);
|
|
15401
|
+
span.setAttribute('http.request.body', bodyStr);
|
|
15402
|
+
console.log(`[SignOz] ${method} Request to ${url} from page ${pagePath}:`, bodyStr);
|
|
15403
|
+
}
|
|
15404
|
+
this.addEventListener('load', function () {
|
|
15405
|
+
span.setAttribute('http.status_code', xhr.status);
|
|
15406
|
+
// Log response body
|
|
15407
|
+
if (config.logResponseBody && xhr.status >= 200 && xhr.status < 300) {
|
|
15408
|
+
const responseData = xhr.responseText;
|
|
15409
|
+
const truncatedData = truncateBody(responseData, config.maxBodyLogSize);
|
|
15410
|
+
span.setAttribute('http.response.body', truncatedData);
|
|
15411
|
+
console.log(`[SignOz] ${method} Response from ${url} (${xhr.status}) on page ${pagePath}:`, truncatedData);
|
|
15412
|
+
}
|
|
15413
|
+
else if (xhr.status >= 300) {
|
|
15414
|
+
console.log(`[SignOz] ${method} Request to ${url} from page ${pagePath} - Status: ${xhr.status}`);
|
|
15415
|
+
}
|
|
15416
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
15417
|
+
span.end();
|
|
15418
|
+
});
|
|
15419
|
+
this.addEventListener('error', function () {
|
|
15420
|
+
span.recordException(new Error('XHR request failed'));
|
|
15421
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: 'XHR request failed' });
|
|
15422
|
+
console.error(`[SignOz] ${method} Error for ${url} on page ${pagePath}`);
|
|
15423
|
+
span.end();
|
|
15424
|
+
});
|
|
15425
|
+
return originalSend.call(this, body);
|
|
15426
|
+
};
|
|
15427
|
+
return xhr;
|
|
15428
|
+
};
|
|
15429
|
+
}
|
|
15430
|
+
// Fungsi untuk menambahkan error tracking
|
|
15431
|
+
function addErrorTracking() {
|
|
15432
|
+
// Track unhandled errors
|
|
15433
|
+
window.addEventListener('error', (event) => {
|
|
15434
|
+
var _a;
|
|
15435
|
+
const tracer = trace.getTracer('error-tracker');
|
|
15436
|
+
const span = tracer.startSpan('Unhandled Error');
|
|
15437
|
+
span.setAttribute('error.type', 'unhandled');
|
|
15438
|
+
span.setAttribute('error.message', event.message);
|
|
15439
|
+
span.setAttribute('error.filename', event.filename || 'unknown');
|
|
15440
|
+
span.setAttribute('error.lineno', event.lineno || 0);
|
|
15441
|
+
span.setAttribute('error.colno', event.colno || 0);
|
|
15442
|
+
if (event.error) {
|
|
15443
|
+
span.recordException(event.error);
|
|
15444
|
+
span.setAttribute('error.stack', event.error.stack || '');
|
|
15445
|
+
}
|
|
15446
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: event.message });
|
|
15447
|
+
console.error('[SignOz] Unhandled Error:', {
|
|
15448
|
+
message: event.message,
|
|
15449
|
+
filename: event.filename,
|
|
15450
|
+
lineno: event.lineno,
|
|
15451
|
+
colno: event.colno,
|
|
15452
|
+
stack: (_a = event.error) === null || _a === void 0 ? void 0 : _a.stack
|
|
15453
|
+
});
|
|
15454
|
+
span.end();
|
|
15455
|
+
});
|
|
15456
|
+
// Track unhandled promise rejections
|
|
15457
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
15458
|
+
const tracer = trace.getTracer('error-tracker');
|
|
15459
|
+
const span = tracer.startSpan('Unhandled Promise Rejection');
|
|
15460
|
+
span.setAttribute('error.type', 'unhandled_rejection');
|
|
15461
|
+
span.setAttribute('error.reason', String(event.reason));
|
|
15462
|
+
if (event.reason instanceof Error) {
|
|
15463
|
+
span.recordException(event.reason);
|
|
15464
|
+
span.setAttribute('error.message', event.reason.message);
|
|
15465
|
+
span.setAttribute('error.stack', event.reason.stack || '');
|
|
15466
|
+
}
|
|
15467
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: String(event.reason) });
|
|
15468
|
+
console.error('[SignOz] Unhandled Promise Rejection:', event.reason);
|
|
15469
|
+
span.end();
|
|
15470
|
+
});
|
|
15471
|
+
}
|
|
15472
|
+
// Fungsi untuk menambahkan navigation tracking
|
|
15473
|
+
function addNavigationTracking() {
|
|
15474
|
+
let previousUrl = window.location.href;
|
|
15475
|
+
// Track initial page load
|
|
15476
|
+
const tracer = trace.getTracer('navigation-tracker');
|
|
15477
|
+
const initialSpan = tracer.startSpan('Page Load');
|
|
15478
|
+
initialSpan.setAttribute('navigation.type', 'initial');
|
|
15479
|
+
initialSpan.setAttribute('navigation.url', window.location.href);
|
|
15480
|
+
initialSpan.setAttribute('navigation.pathname', window.location.pathname);
|
|
15481
|
+
initialSpan.setAttribute('navigation.search', window.location.search);
|
|
15482
|
+
initialSpan.setAttribute('navigation.hash', window.location.hash);
|
|
15483
|
+
console.log('[SignOz] Page Load:', {
|
|
15484
|
+
url: window.location.href,
|
|
15485
|
+
pathname: window.location.pathname
|
|
15486
|
+
});
|
|
15487
|
+
initialSpan.end();
|
|
15488
|
+
// Track popstate (browser back/forward)
|
|
15489
|
+
window.addEventListener('popstate', () => {
|
|
15490
|
+
const span = tracer.startSpan('Navigation');
|
|
15491
|
+
span.setAttribute('navigation.type', 'popstate');
|
|
15492
|
+
span.setAttribute('navigation.from', previousUrl);
|
|
15493
|
+
span.setAttribute('navigation.to', window.location.href);
|
|
15494
|
+
span.setAttribute('navigation.pathname', window.location.pathname);
|
|
15495
|
+
span.setAttribute('navigation.search', window.location.search);
|
|
15496
|
+
span.setAttribute('navigation.hash', window.location.hash);
|
|
15497
|
+
console.log('[SignOz] Navigation (popstate):', {
|
|
15498
|
+
from: previousUrl,
|
|
15499
|
+
to: window.location.href,
|
|
15500
|
+
pathname: window.location.pathname
|
|
15501
|
+
});
|
|
15502
|
+
previousUrl = window.location.href;
|
|
15503
|
+
span.end();
|
|
15504
|
+
});
|
|
15505
|
+
// Track pushState and replaceState (SPA navigation)
|
|
15506
|
+
const originalPushState = history.pushState;
|
|
15507
|
+
history.pushState = function (...args) {
|
|
15508
|
+
const span = tracer.startSpan('Navigation');
|
|
15509
|
+
span.setAttribute('navigation.type', 'pushState');
|
|
15510
|
+
span.setAttribute('navigation.from', previousUrl);
|
|
15511
|
+
const result = originalPushState.apply(this, args);
|
|
15512
|
+
span.setAttribute('navigation.to', window.location.href);
|
|
15513
|
+
span.setAttribute('navigation.pathname', window.location.pathname);
|
|
15514
|
+
span.setAttribute('navigation.search', window.location.search);
|
|
15515
|
+
span.setAttribute('navigation.hash', window.location.hash);
|
|
15516
|
+
console.log('[SignOz] Navigation (pushState):', {
|
|
15517
|
+
from: previousUrl,
|
|
15518
|
+
to: window.location.href,
|
|
15519
|
+
pathname: window.location.pathname
|
|
15520
|
+
});
|
|
15521
|
+
previousUrl = window.location.href;
|
|
15522
|
+
span.end();
|
|
15523
|
+
return result;
|
|
15524
|
+
};
|
|
15525
|
+
const originalReplaceState = history.replaceState;
|
|
15526
|
+
history.replaceState = function (...args) {
|
|
15527
|
+
const span = tracer.startSpan('Navigation');
|
|
15528
|
+
span.setAttribute('navigation.type', 'replaceState');
|
|
15529
|
+
span.setAttribute('navigation.from', previousUrl);
|
|
15530
|
+
const result = originalReplaceState.apply(this, args);
|
|
15531
|
+
span.setAttribute('navigation.to', window.location.href);
|
|
15532
|
+
span.setAttribute('navigation.pathname', window.location.pathname);
|
|
15533
|
+
span.setAttribute('navigation.search', window.location.search);
|
|
15534
|
+
span.setAttribute('navigation.hash', window.location.hash);
|
|
15535
|
+
console.log('[SignOz] Navigation (replaceState):', {
|
|
15536
|
+
from: previousUrl,
|
|
15537
|
+
to: window.location.href,
|
|
15538
|
+
pathname: window.location.pathname
|
|
15539
|
+
});
|
|
15540
|
+
previousUrl = window.location.href;
|
|
15541
|
+
span.end();
|
|
15542
|
+
return result;
|
|
15543
|
+
};
|
|
15544
|
+
}
|
|
15300
15545
|
/**
|
|
15301
15546
|
* Inisialisasi SignOz tracing untuk aplikasi React
|
|
15302
15547
|
* @param config - Konfigurasi SignOz (opsional, akan menggunakan environment variables jika tidak disediakan)
|
|
@@ -15320,7 +15565,14 @@ function initializeSignOzTracing(config) {
|
|
|
15320
15565
|
scheduledDelayMillis: 5000,
|
|
15321
15566
|
exportTimeoutMillis: 30000
|
|
15322
15567
|
},
|
|
15323
|
-
allowedOrigins: (config === null || config === void 0 ? void 0 : config.allowedOrigins) || parseAllowedOrigins(getConfigValue('REACT_APP_SIGNOZ_ALLOWED_ORIGINS'))
|
|
15568
|
+
allowedOrigins: (config === null || config === void 0 ? void 0 : config.allowedOrigins) || parseAllowedOrigins(getConfigValue('REACT_APP_SIGNOZ_ALLOWED_ORIGINS')),
|
|
15569
|
+
enableRequestLogging: (config === null || config === void 0 ? void 0 : config.enableRequestLogging) !== undefined ? config.enableRequestLogging : (getConfigValue('REACT_APP_SIGNOZ_ENABLE_REQUEST_LOGGING') === 'true' || true),
|
|
15570
|
+
logRequestBody: (config === null || config === void 0 ? void 0 : config.logRequestBody) !== undefined ? config.logRequestBody : (getConfigValue('REACT_APP_SIGNOZ_LOG_REQUEST_BODY') === 'true' || true),
|
|
15571
|
+
logResponseBody: (config === null || config === void 0 ? void 0 : config.logResponseBody) !== undefined ? config.logResponseBody : (getConfigValue('REACT_APP_SIGNOZ_LOG_RESPONSE_BODY') === 'true' || true),
|
|
15572
|
+
maxBodyLogSize: (config === null || config === void 0 ? void 0 : config.maxBodyLogSize) || parseInt(getConfigValue('REACT_APP_SIGNOZ_MAX_BODY_LOG_SIZE') || '10000') || 10000,
|
|
15573
|
+
enableDocumentLoad: (config === null || config === void 0 ? void 0 : config.enableDocumentLoad) !== undefined ? config.enableDocumentLoad : (getConfigValue('REACT_APP_SIGNOZ_ENABLE_DOCUMENT_LOAD') !== 'false'),
|
|
15574
|
+
enableErrorTracking: (config === null || config === void 0 ? void 0 : config.enableErrorTracking) !== undefined ? config.enableErrorTracking : (getConfigValue('REACT_APP_SIGNOZ_ENABLE_ERROR_TRACKING') !== 'false'),
|
|
15575
|
+
enableNavigationTracking: (config === null || config === void 0 ? void 0 : config.enableNavigationTracking) !== undefined ? config.enableNavigationTracking : (getConfigValue('REACT_APP_SIGNOZ_ENABLE_NAVIGATION_TRACKING') !== 'false')
|
|
15324
15576
|
};
|
|
15325
15577
|
// Validasi konfigurasi
|
|
15326
15578
|
const { isValid, missingFields } = validateConfig(effectiveConfig);
|
|
@@ -15370,14 +15622,52 @@ function initializeSignOzTracing(config) {
|
|
|
15370
15622
|
'@opentelemetry/instrumentation-fetch': {
|
|
15371
15623
|
propagateTraceHeaderCorsUrls: effectiveConfig.allowedOrigins,
|
|
15372
15624
|
},
|
|
15625
|
+
// Nonaktifkan user interaction instrumentation (click events)
|
|
15626
|
+
'@opentelemetry/instrumentation-user-interaction': {
|
|
15627
|
+
enabled: false,
|
|
15628
|
+
},
|
|
15629
|
+
// Document load instrumentation untuk page load performance
|
|
15630
|
+
'@opentelemetry/instrumentation-document-load': {
|
|
15631
|
+
enabled: effectiveConfig.enableDocumentLoad,
|
|
15632
|
+
},
|
|
15373
15633
|
}),
|
|
15374
15634
|
],
|
|
15375
15635
|
});
|
|
15636
|
+
// Tambahkan custom logging untuk request/response
|
|
15637
|
+
if (effectiveConfig.enableRequestLogging) {
|
|
15638
|
+
addFetchLogging({
|
|
15639
|
+
enableRequestLogging: effectiveConfig.enableRequestLogging,
|
|
15640
|
+
logRequestBody: effectiveConfig.logRequestBody,
|
|
15641
|
+
logResponseBody: effectiveConfig.logResponseBody,
|
|
15642
|
+
maxBodyLogSize: effectiveConfig.maxBodyLogSize
|
|
15643
|
+
});
|
|
15644
|
+
addXHRLogging({
|
|
15645
|
+
enableRequestLogging: effectiveConfig.enableRequestLogging,
|
|
15646
|
+
logRequestBody: effectiveConfig.logRequestBody,
|
|
15647
|
+
logResponseBody: effectiveConfig.logResponseBody,
|
|
15648
|
+
maxBodyLogSize: effectiveConfig.maxBodyLogSize
|
|
15649
|
+
});
|
|
15650
|
+
}
|
|
15651
|
+
// Tambahkan error tracking
|
|
15652
|
+
if (effectiveConfig.enableErrorTracking) {
|
|
15653
|
+
addErrorTracking();
|
|
15654
|
+
}
|
|
15655
|
+
// Tambahkan navigation tracking
|
|
15656
|
+
if (effectiveConfig.enableNavigationTracking) {
|
|
15657
|
+
addNavigationTracking();
|
|
15658
|
+
}
|
|
15376
15659
|
console.log('SignOz: Konfigurasi tracing:', {
|
|
15377
15660
|
serviceName: effectiveConfig.serviceName,
|
|
15378
15661
|
environment: effectiveConfig.environment,
|
|
15379
15662
|
allowedOrigins: effectiveConfig.allowedOrigins,
|
|
15380
|
-
traceSampleRate: effectiveConfig.traceSampleRate
|
|
15663
|
+
traceSampleRate: effectiveConfig.traceSampleRate,
|
|
15664
|
+
enableRequestLogging: effectiveConfig.enableRequestLogging,
|
|
15665
|
+
logRequestBody: effectiveConfig.logRequestBody,
|
|
15666
|
+
logResponseBody: effectiveConfig.logResponseBody,
|
|
15667
|
+
maxBodyLogSize: effectiveConfig.maxBodyLogSize,
|
|
15668
|
+
enableDocumentLoad: effectiveConfig.enableDocumentLoad,
|
|
15669
|
+
enableErrorTracking: effectiveConfig.enableErrorTracking,
|
|
15670
|
+
enableNavigationTracking: effectiveConfig.enableNavigationTracking
|
|
15381
15671
|
});
|
|
15382
15672
|
console.log('SignOz: Tracing berhasil diinisialisasi');
|
|
15383
15673
|
}
|