在前面的許多 demo 中,我們橫跨了前端、後端、第三方 API、資料庫等多個系統。本篇文章將串聯所有的 demo,來看看 Sentry 是如何呈現的。
複用之前的React+Sentry的 demo,然後加上呼叫後端Node api的邏輯---
import * as Sentry from '@sentry/react';
import React, { useState } from 'react';
import { SENTRY_ENDPOINT, NODEJS_SERVICE_URL } from './config';
import './App.css';
Sentry.init({
dsn: SENTRY_ENDPOINT,
integrations: [
Sentry.browserTracingIntegration(),
Sentry.browserProfilingIntegration(),
Sentry.replayIntegration(),
],
// Tracing
tracesSampleRate: 1.0, });
function App() {
const [isFetching, setIsFetching] = useState(false);
const clickHandler = async () => {
setIsFetching(true);
const url = `${NODEJS_SERVICE_URL}/demo`;
try {
const res = await fetch(url, { method: 'GET' });
const data = await res.json();
alert('Fetch Successfully');
} catch (err) {
console.error(err);
} finally {
setIsFetching(false);
}
};
return (
<div>
<h1>Hello Sentry</h1>
{!isFetching ? (
<button onClick={() => clickHandler()}>
Call NodeJS Service
</button>
) : (
<div>is fetching...</div>
)}
</div>
);
}
export default App;
同樣也是沿用之前的NodeJS+Sentry的demo,然後在同一支api中再呼叫另一個service(Python FastAPI demo)以及mock的 postgresql 操作:
app.get('/demo', async (req, res) => {
const pyResult = await axios.get(`${PYTHON_SERVICE_URL}/python-api`);
const pgResult = await pgClient.query('SELECT pg_sleep(5);'); // 模擬 5 秒的耗時操作
res.json({ message: 'demo api successfully' });
});
為了讓Sentry也能監控到Python service,我們也在Sentry平台上再新增一個project、獲取到新的DSN,同時在Python Fastapi專案裡面使用pip install --upgrade 'sentry-sdk[fastapi]'
來安裝python sentry sdk---
from fastapi import FastAPI
import uvicorn
from config import PORT, SENTRY_DSN
import sentry_sdk
sentry_sdk.init(
dsn=SENTRY_DSN,
traces_sample_rate=1.0,
profiles_sample_rate=1.0,
)
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello, World!"}
@app.get("/python-api")
def long_api():
sum = 0
# mock 耗時操作
for i in range(1000000):
sum +=1
return {"message": "python long-service successfully"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=PORT)
從前端觸發請求後,查看sentry的Trace
(免費版的sentry沒辦法同時顯示多個專案)
可以看到,Sentry可以追蹤不同的應用在同一個Project裡面,並且把同一個請求鏈歸類到同一個trace id。
請求間的 Trace ID 和 Baggage 可以透過 HTTP headers 進行傳遞和串接。我們可以打印看看所有服務請求的header:
{
host: 'localhost:3030',
connection: 'keep-alive',
'sec-ch-ua': '"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"',
baggage: 'sentry-environment=production,sentry-public_key=fdcf31e5f9b89c2086c878ba04caada9,sentry-trace_id=282bec999ac14ac88f92c7c4bfa41f16,sentry-sample_rate=1,sentry-sampled=true',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',
'sentry-trace': '282bec999ac14ac88f92c7c4bfa41f16-a8b4d9eeef619668-1',
'sec-ch-ua-platform': '"macOS"',
accept: '*/*',
origin: 'http://localhost:5173',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:5173/',
'accept-encoding': 'gzip, deflate, br, zstd',
'accept-language': 'en-US,en;q=0.9,zh-TW;q=0.8,zh;q=0.7',
'if-none-match': 'W/"23-W/YsZ9Tu+q5Dm5TDOmsmox0nPro"'
}
Headers({
accept: 'application/json, text/plain, */*',
'user-agent': 'axios/1.7.7',
'accept-encoding': 'gzip, compress, deflate, br',
'sentry-trace': '282bec999ac14ac88f92c7c4bfa41f16-83a9c1fa172aa41d-1',
baggage:
'sentry-environment=production,sentry-public_key=fdcf31e5f9b89c2086c878ba04caada9,sentry-trace_id=282bec999ac14ac88f92c7c4bfa41f16,sentry-sample_rate=1,sentry-sampled=true',
host: 'localhost:3040',
connection: 'keep-alive',
});
從這裡可以看到,sentry-trace
和baggage
的資訊貫穿了整個請求鏈路,Sentry就是透過他們來記錄、更新服務間的追蹤資訊,達到串連的效果。
透過 Sentry 的 sentry-trace
和 baggage
headers,我們可以實現多個服務的全鏈路追蹤,即使這些服務橫跨了前端、後端NodeJS、Python FastAPI 服務和資料庫操作。Sentry 會將相同請求鏈中的所有操作歸類到同一個 Trace ID,使得我們可以在 Sentry 的儀表板中查看跨服務的請求性能和錯誤細節,這對於調試和性能優化來說非常有幫助。
本文程式碼可以在此 Github repository查看。
!!! 這篇解答我好多事情'sentry-trace': '282bec999ac14ac88f92c7c4bfa41f16-a8b4d9eeef619668-1'
這個跟OpenTelemetry 格式有一點點不同, 但可兼容.
// trace context 如下
Value = 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba9
02b7-01
// 能拆解成這三個資料
TraceId = 4bf92f3577b34da6a3ce929d0e0e4736
Parent SpanId = 00f067aa0ba902b7
Trace-flags = 00000001 // 採取取樣
baggage 倒是一樣, 原來sentry 有tracing 的瀑布圖!!!
難怪很多人說 我就有 sentry 了何必用OpenTelemetry (疑
應該是Sentry也有接入Opentelemetry,但覆蓋了header的寫法(這部分還需要trace一下原始碼確認確認)
不過使用Sentry也是某種程度上在用Opentelemetry(?
更準確是借鑒
因為要說有在使用必須是他的exporter能選擇使用Opentelemetry格式,但還沒正式release
https://develop.sentry.dev/sdk/telemetry/traces/opentelemetry/
When Sentry performance monitoring was initially introduced, OpenTelemetry was in early stages. This lead to us adopt a slightly different model from OpenTelemetry