Skip to content

Commit 6fc6a26

Browse files
committed
add react spa to examples
1 parent 67d4173 commit 6fc6a26

File tree

14 files changed

+745
-2
lines changed

14 files changed

+745
-2
lines changed

examples/web/.babelrc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"presets": [
3+
["@babel/preset-env", {
4+
"targets": {
5+
"browsers": ["last 2 versions"]
6+
}
7+
}],
8+
["@babel/preset-react", {
9+
"runtime": "automatic"
10+
}]
11+
]
12+
}

examples/web/examples/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ <h1>OpenTelemetry Web Examples</h1>
3535
<ul>
3636
<li><a href="/document-load/">📄 Document Load Instrumentation</a></li>
3737
<li><a href="/navigation/">🧭 Navigation Instrumentation</a></li>
38+
<li><a href="/react-spa/">⚛️ React SPA Navigation Demo</a></li>
3839
<li>
3940
<a href="/user-interaction/">👆 User Interaction Instrumentation</a>
4041
</li>
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>React SPA - OpenTelemetry Navigation Demo</title>
7+
<style>
8+
/* Reset and base styles */
9+
* {
10+
margin: 0;
11+
padding: 0;
12+
box-sizing: border-box;
13+
}
14+
15+
body {
16+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
17+
background-color: #f5f5f5;
18+
}
19+
20+
/* Loading spinner */
21+
.loading {
22+
display: flex;
23+
justify-content: center;
24+
align-items: center;
25+
height: 100vh;
26+
flex-direction: column;
27+
}
28+
29+
.spinner {
30+
width: 40px;
31+
height: 40px;
32+
border: 4px solid #f3f3f3;
33+
border-top: 4px solid #3498db;
34+
border-radius: 50%;
35+
animation: spin 1s linear infinite;
36+
margin-bottom: 1rem;
37+
}
38+
39+
@keyframes spin {
40+
0% { transform: rotate(0deg); }
41+
100% { transform: rotate(360deg); }
42+
}
43+
44+
.loading-text {
45+
color: #666;
46+
font-size: 1.1rem;
47+
}
48+
49+
/* Hide loading when React app loads */
50+
#root:not(:empty) + .loading {
51+
display: none;
52+
}
53+
</style>
54+
</head>
55+
<body>
56+
<!-- React app will mount here -->
57+
<div id="root"></div>
58+
59+
<!-- Loading indicator shown while React app loads -->
60+
<div class="loading">
61+
<div class="spinner"></div>
62+
<div class="loading-text">Loading React SPA Navigation Demo...</div>
63+
</div>
64+
65+
<!-- OpenTelemetry and React app bundle -->
66+
<script type="text/javascript" src="/react-spa.js"></script>
67+
68+
<script>
69+
// Add some global debugging helpers
70+
window.addEventListener('load', () => {
71+
console.log('🎯 Page loaded - Navigation instrumentation should be active');
72+
73+
// Log initial page load
74+
console.log('📍 Initial URL:', window.location.href);
75+
76+
// Add keyboard shortcuts for testing
77+
document.addEventListener('keydown', (e) => {
78+
if (e.ctrlKey || e.metaKey) {
79+
switch(e.key) {
80+
case '1':
81+
e.preventDefault();
82+
window.otelDebug?.testNavigation('/');
83+
break;
84+
case '2':
85+
e.preventDefault();
86+
window.otelDebug?.testNavigation('/about');
87+
break;
88+
case '3':
89+
e.preventDefault();
90+
window.otelDebug?.testNavigation('/products');
91+
break;
92+
case '4':
93+
e.preventDefault();
94+
window.otelDebug?.testNavigation('/contact');
95+
break;
96+
case 'h':
97+
e.preventDefault();
98+
window.otelDebug?.testHashNavigation('#test-section');
99+
break;
100+
}
101+
}
102+
});
103+
104+
console.log('⌨️ Keyboard shortcuts available:');
105+
console.log(' Ctrl/Cmd + 1-4: Navigate to pages');
106+
console.log(' Ctrl/Cmd + H: Test hash navigation');
107+
});
108+
109+
// Track navigation performance
110+
if ('navigation' in window.performance) {
111+
window.addEventListener('load', () => {
112+
const navTiming = performance.getEntriesByType('navigation')[0];
113+
console.log('⏱️ Navigation timing:', {
114+
domContentLoaded: navTiming.domContentLoadedEventEnd - navTiming.domContentLoadedEventStart,
115+
loadComplete: navTiming.loadEventEnd - navTiming.loadEventStart,
116+
totalTime: navTiming.loadEventEnd - navTiming.fetchStart
117+
});
118+
});
119+
}
120+
121+
// Monitor hash changes
122+
window.addEventListener('hashchange', (e) => {
123+
console.log('🔗 Hash changed:', {
124+
from: e.oldURL,
125+
to: e.newURL,
126+
hash: window.location.hash
127+
});
128+
});
129+
130+
// Monitor popstate events
131+
window.addEventListener('popstate', (e) => {
132+
console.log('⬅️ Popstate event:', {
133+
state: e.state,
134+
url: window.location.href
135+
});
136+
});
137+
</script>
138+
</body>
139+
</html>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom/client';
3+
import { logs } from '@opentelemetry/api-logs';
4+
import {
5+
LoggerProvider,
6+
SimpleLogRecordProcessor,
7+
ConsoleLogRecordExporter,
8+
} from '@opentelemetry/sdk-logs';
9+
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
10+
import { registerInstrumentations } from '@opentelemetry/instrumentation';
11+
import { resourceFromAttributes } from '@opentelemetry/resources';
12+
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
13+
import { BrowserNavigationInstrumentation } from '@opentelemetry/instrumentation-browser-navigation';
14+
import App from './src/App';
15+
16+
// Initialize OpenTelemetry logging
17+
const loggerProvider = new LoggerProvider({
18+
resource: resourceFromAttributes({
19+
[ATTR_SERVICE_NAME]: 'react-spa-navigation-demo',
20+
}),
21+
});
22+
23+
// Add console exporter for development
24+
loggerProvider.addLogRecordProcessor(
25+
new SimpleLogRecordProcessor(new ConsoleLogRecordExporter())
26+
);
27+
28+
// Add OTLP HTTP exporter to send logs to server
29+
loggerProvider.addLogRecordProcessor(
30+
new SimpleLogRecordProcessor(new OTLPLogExporter({
31+
url: 'http://localhost:4318/v1/logs', // Standard OTLP endpoint
32+
headers: {
33+
'Content-Type': 'application/json',
34+
},
35+
}))
36+
);
37+
38+
// Set the global logger provider
39+
logs.setGlobalLoggerProvider(loggerProvider);
40+
41+
// Register the browser navigation instrumentation
42+
registerInstrumentations({
43+
instrumentations: [
44+
new BrowserNavigationInstrumentation({
45+
enabled: true,
46+
useNavigationApiIfAvailable: true, // Re-enable Navigation API
47+
applyCustomLogRecordData: logRecord => {
48+
if (!logRecord.attributes) {
49+
logRecord.attributes = {};
50+
}
51+
// Add custom attributes to navigation events
52+
logRecord.attributes['app.type'] = 'react-spa';
53+
logRecord.attributes['app.framework'] = 'react';
54+
logRecord.attributes['app.version'] = '1.0.0';
55+
56+
// Add timestamp for better tracking
57+
logRecord.attributes['navigation.timestamp'] = Date.now();
58+
},
59+
}),
60+
],
61+
});
62+
63+
// Create React root and render the app
64+
const root = ReactDOM.createRoot(document.getElementById('root'));
65+
root.render(
66+
<React.StrictMode>
67+
<App />
68+
</React.StrictMode>
69+
);

0 commit comments

Comments
 (0)