iT邦幫忙

2024 iThome 鐵人賽

DAY 27
1
DevOps

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

Day27--手寫在 Otel 中的前端 tracing data

  • 分享至 

  • xImage
  •  

前言

根據前篇我們知道,Opentelemetry 在前端實現tracing,是需要覆蓋全局 fetch、或者全局的 XMLHttpRequest。本文我們就來實現這兩者,然後透過 call 一個簡單後端 api,從後端打印 request header,看我們有沒有覆蓋成功。

self sdk

簡單寫一個sdk配置,在初始化的時候就宣告我們自己寫的 instrumentations,在start的時候就讓所有的 instrmentations 也初始化:

export class MockWebSdk {
    constructor() {
        this.instruments = [
            new MockFetchInstrumentation(),
            new MockXMLHttpRequestInstrumentation(),
        ];
    }
    start() {
        this.instruments.forEach((instruments) => {
            instruments.init();
        });
    }
}

然後在 React 的入口文件main.js中的最上層引入並初始化:

import { MockWebSdk } from './self-otel/sdk.js';
const sdk = new MockWebSdk();
sdk.start();

...

createRoot(document.getElementById('root')).render(
    <StrictMode>
        <App />
    </StrictMode>,
);

覆蓋fetch

跟之前覆蓋 http 很類似,就是先獲取原本的 fetch 方法

const originalFetch = window.fetch;

然後利用window.fetch = callback 來覆蓋全局的fetch。

window.fetch = async (...args) => {
    let [resource, config] = args;

    // Create a new configuration object if not provided
    config = config || {};

    // Ensure headers object exists
    config.headers = config.headers || {};
}

獲取或新建一個 request config,然後在header 中增加traceparent屬性,完成 tracing 的第一步。(這邊就簡單把traceparent的值寫成 '00-fetchTraceId-mockspanId-01'

然後再將原本的 fetch 返回

return originalFetch(resource, config)
    .then((response) => {
        // TODO: exporter logic
        return response;
    })
    .catch((error) => {
        throw error;
    });

測試,呼叫Node api

查看console,可以看到我們的 fetch trace header 成功傳到後端服務了:

image

覆蓋 XMLHttpRequest

也是一樣的思路,XMLHttpRequest是一個物件,我們的覆蓋方式就必須是用繼承

const originalXMLHttpRequest = window.XMLHttpRequest;

class MockXMLHttpRequest extends originalXMLHttpRequest {
        constructor() {
            super(); // Call the original constructor
            this._url = ''; // Store the URL of the request
        }
}

然後主要就是覆寫send方法、來新增 header traceparent屬性 :

send(body) {
    // Add a traceparent header before sending the request
    this.setRequestHeader(
        'traceparent',
        '00-xmlTraceId-mockspanId-01',
    );
    // Call the original send method
    super.send(body);
}

而exporter的邏輯,可以監聽load事件、然後在callback中實現:

this.addEventListener('load', () => {
    // TODO: exporter logic
    console.log(`Request to ${this._url} completed.`);
});

測試,呼叫Node api

查看console,可以看到我們的 xml-http -request trace header 也成功傳到後端服務了:

image

小結

本次demo中,我們詳細介紹了如何在前端實現 OpenTelemetry tracing,通過覆蓋 fetchXMLHttpRequest 兩種常見的網絡請求方式來注入 traceparent header,從而實現 tracing data。這種方式使我們可以將前端的 tracing context 傳遞到後端,從而實現全鏈路監控。

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

ref

ChangeLog

  • 20241011--補上圖片與小結
  • 20240930--基本程式碼內容完成
  • 20240929--初稿大綱

上一篇
Day26--前端與Opentelemetry---以React為例
下一篇
Day28--服務端/客戶端渲染與opentelememtry--以NextJS為例
系列文
全端監控技術筆記---從Sentry到Opentelemetry30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言