iT邦幫忙

2024 iThome 鐵人賽

DAY 13
1
DevOps

全端監控技術筆記---從Sentry到Opentelemetry系列 第 13

Day13---Tracing Data in Sentry

  • 分享至 

  • xImage
  •  

前言

在前面的許多 demo 中,我們橫跨了前端、後端、第三方 API、資料庫等多個系統。本篇文章將串聯所有的 demo,來看看 Sentry 是如何呈現的。

結合之前的demo

前端

複用之前的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服務

同樣也是沿用之前的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' });
});

Python服務

為了讓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。

image

為何可以串接所有服務

請求間的 Trace ID 和 Baggage 可以透過 HTTP headers 進行傳遞和串接。我們可以打印看看所有服務請求的header:

  • nodejs:
{
  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"'
}
  • python fastapi:
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-tracebaggage的資訊貫穿了整個請求鏈路,Sentry就是透過他們來記錄、更新服務間的追蹤資訊,達到串連的效果。

小結

透過 Sentry 的 sentry-tracebaggage headers,我們可以實現多個服務的全鏈路追蹤,即使這些服務橫跨了前端、後端NodeJS、Python FastAPI 服務和資料庫操作。Sentry 會將相同請求鏈中的所有操作歸類到同一個 Trace ID,使得我們可以在 Sentry 的儀表板中查看跨服務的請求性能和錯誤細節,這對於調試和性能優化來說非常有幫助。

本文程式碼可以在此 Github repository查看。

ref

ChangeLog

  • 20240927--補上小結、圖片
  • 20240921--初稿

上一篇
Day12---NodeJS 在Sentry上的性能監控
系列文
全端監控技術筆記---從Sentry到Opentelemetry13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
雷N
iT邦研究生 1 級 ‧ 2024-09-27 10:44:13

!!! 這篇解答我好多事情
'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 (疑

我要留言

立即登入留言