-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(*): add more telemetry and configure tempo properly to expose sp…
…ans metrics
- Loading branch information
1 parent
a712436
commit 6c04ab8
Showing
19 changed files
with
389 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
FROM grafana/otel-lgtm | ||
|
||
COPY tempo-config.yaml . | ||
|
||
CMD /otel-lgtm/run-all.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
server: | ||
http_listen_port: 3200 | ||
grpc_listen_port: 9096 | ||
|
||
distributor: | ||
receivers: | ||
otlp: | ||
protocols: | ||
grpc: | ||
endpoint: "localhost:4417" | ||
http: | ||
endpoint: "localhost:4418" | ||
|
||
storage: | ||
trace: | ||
backend: local | ||
wal: | ||
path: /tmp/tempo/wal | ||
local: | ||
path: /tmp/tempo/blocks | ||
|
||
metrics_generator: | ||
registry: | ||
# A list of labels that will be added to all generated metrics. | ||
external_labels: | ||
source: tempo | ||
processor: | ||
span_metrics: | ||
enable_target_info: true | ||
dimensions: ['react_client.cold_start', 'react_client.page_name', 'react_client.product_id'] | ||
local_blocks: | ||
filter_server_spans: false | ||
traces_storage: | ||
path: /tmp/tempo/generator/traces | ||
storage: | ||
path: /tmp/tempo/generator/wal | ||
remote_write: | ||
- url: http://localhost:9090/api/v1/write | ||
send_exemplars: true | ||
|
||
overrides: | ||
defaults: | ||
metrics_generator: | ||
processors: [service-graphs, span-metrics, local-blocks] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { FC, PropsWithChildren, useEffect, useRef } from "react"; | ||
import { Attributes } from "@opentelemetry/api"; | ||
import useTrackPageView from "../../hooks/useTrackPageView"; | ||
import useSpansContext from "../SpansProvider/hooks/useSpansContext"; | ||
|
||
type PageProps = { | ||
isLoading?: boolean; | ||
instrumentation: { | ||
pageName: string; | ||
attributes?: Attributes; | ||
}; | ||
}; | ||
|
||
const Page: FC<PropsWithChildren<PageProps>> = ({ | ||
children, | ||
instrumentation, | ||
isLoading, | ||
}) => { | ||
const wasColdStart = useRef(window.coldStart); | ||
|
||
const { pageName, attributes } = instrumentation; | ||
const { endSpan, getOrCreateSpan } = useSpansContext(); | ||
|
||
getOrCreateSpan("Page Ready", { | ||
startTime: wasColdStart.current | ||
? performance.timeOrigin | ||
: new Date().getTime(), | ||
attributes: { | ||
"react_client.cold_start": wasColdStart.current, | ||
"react_client.page_name": pageName, | ||
...attributes, | ||
}, | ||
}); | ||
|
||
useEffect(() => { | ||
if (window.coldStart) { | ||
window.coldStart = false; | ||
} | ||
}, []); | ||
|
||
useEffect(() => { | ||
if (isLoading === undefined || !isLoading) { | ||
endSpan("Page Ready"); | ||
} | ||
}, [endSpan, isLoading]); | ||
|
||
useTrackPageView(pageName, attributes); | ||
|
||
if (isLoading) { | ||
return "Loading"; | ||
} | ||
|
||
return <>{children}</>; | ||
}; | ||
|
||
export default Page; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import Page from "./Page"; | ||
|
||
export default Page; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { SpansContext } from "./hooks/useSpansContext"; | ||
import { FC, PropsWithChildren, useCallback, useRef } from "react"; | ||
import { context, Span, SpanOptions, trace } from "@opentelemetry/api"; | ||
import { SpanName } from "./constants/spans"; | ||
|
||
const SpansProvider: FC<PropsWithChildren> = ({ children }) => { | ||
const spansRef = useRef<Map<SpanName, Span>>(new Map()); | ||
|
||
const getOrCreateSpan = useCallback( | ||
(name: SpanName, options?: SpanOptions): [Span, boolean] => { | ||
if (spansRef.current.has(name)) { | ||
return [spansRef.current.get(name)!, false]; | ||
} | ||
|
||
const tracer = trace.getTracer("react-client"); | ||
const span = tracer.startSpan(name, options); | ||
|
||
spansRef.current.set(name, span); | ||
|
||
return [span, true]; | ||
}, | ||
[], | ||
); | ||
|
||
const withSpanContext = useCallback( | ||
(name: SpanName, callback: () => void) => { | ||
const [span] = getOrCreateSpan(name); | ||
context.with(trace.setSpan(context.active(), span), callback); | ||
}, | ||
[getOrCreateSpan], | ||
); | ||
|
||
const endSpan = useCallback((name: SpanName) => { | ||
const span = spansRef.current.get(name); | ||
|
||
if (span) { | ||
span.end(); | ||
spansRef.current.delete(name); | ||
} | ||
}, []); | ||
|
||
return ( | ||
<SpansContext.Provider | ||
value={{ getOrCreateSpan, withSpanContext, endSpan }} | ||
> | ||
{children} | ||
</SpansContext.Provider> | ||
); | ||
}; | ||
|
||
export default SpansProvider; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
type SpanName = "Page Ready" | "Purchase Flow"; | ||
|
||
export { type SpanName }; |
28 changes: 28 additions & 0 deletions
28
frontend/src/components/SpansProvider/hooks/useSpansContext.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { createContext, useContext } from "react"; | ||
import { Span, SpanOptions } from "@opentelemetry/api"; | ||
import { SpanName } from "../constants/spans"; | ||
|
||
type SpansContextValue = { | ||
getOrCreateSpan: (name: SpanName, options?: SpanOptions) => [Span, boolean]; | ||
withSpanContext: (name: SpanName, callback: () => void) => void; | ||
endSpan: (name: SpanName) => void; | ||
}; | ||
|
||
const SpansContext = createContext<SpansContextValue>({ | ||
getOrCreateSpan: () => { | ||
throw new Error("ActiveSpanContextValue not provided"); | ||
}, | ||
withSpanContext: () => { | ||
throw new Error("ActiveSpanContextValue not provided"); | ||
}, | ||
endSpan: () => { | ||
throw new Error("ActiveSpanContextValue not provided"); | ||
}, | ||
}); | ||
|
||
const useSpansContext = () => { | ||
return useContext(SpansContext); | ||
}; | ||
|
||
export default useSpansContext; | ||
export { SpansContext }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { useEffect, useRef } from "react"; | ||
import { Attributes, trace } from "@opentelemetry/api"; | ||
|
||
type UseMeasureReadinessArgs = { | ||
pageName: string; | ||
areNetworkRequestsDone?: boolean; | ||
}; | ||
|
||
const useMeasureReadiness = ( | ||
{ pageName, areNetworkRequestsDone }: UseMeasureReadinessArgs, | ||
extraAttributes: Attributes = {}, | ||
) => { | ||
const now = useRef<number>( | ||
window.coldStart ? performance.timeOrigin : new Date().getTime(), | ||
); | ||
|
||
useEffect(() => { | ||
if (window.coldStart) { | ||
window.coldStart = false; | ||
} | ||
}, []); | ||
|
||
useEffect(() => { | ||
const tracer = trace.getTracer("react-client"); | ||
|
||
if (areNetworkRequestsDone === undefined || areNetworkRequestsDone) { | ||
const span = tracer.startSpan("Page Ready", { | ||
startTime: now.current, | ||
}); | ||
|
||
span.setAttributes({ | ||
page_name: pageName, | ||
...extraAttributes, | ||
}); | ||
|
||
span.end(); | ||
} | ||
}, [areNetworkRequestsDone]); | ||
}; | ||
|
||
export default useMeasureReadiness; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Attributes, metrics } from "@opentelemetry/api"; | ||
import { useEffect } from "react"; | ||
|
||
const useTrackPageView = ( | ||
pageName: string, | ||
extraAttributes: Attributes = {}, | ||
) => { | ||
useEffect(() => { | ||
const meter = metrics.getMeter("react-client"); | ||
|
||
const counter = meter.createCounter("react_client_page_view", { | ||
description: "Number of views for a page", | ||
}); | ||
|
||
counter.add(1, { | ||
"react_client.page_name": pageName, | ||
...extraAttributes, | ||
}); | ||
// Make sure this only runs once | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
}; | ||
|
||
export default useTrackPageView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,8 @@ | ||
import React from 'react' | ||
import ReactDOM from 'react-dom/client' | ||
import App from './App.tsx' | ||
import './index.css' | ||
import {setupOTelSDK} from "./otel.ts"; | ||
import ReactDOM from "react-dom/client"; | ||
import App from "./App.tsx"; | ||
import "./index.css"; | ||
import { setupOTelSDK } from "./otel.ts"; | ||
|
||
setupOTelSDK(); | ||
|
||
ReactDOM.createRoot(document.getElementById('root')!).render( | ||
<React.StrictMode> | ||
<App /> | ||
</React.StrictMode>, | ||
) | ||
ReactDOM.createRoot(document.getElementById("root")!).render(<App />); |
Oops, something went wrong.