В этом посте мы собираемся углубиться в создание пакета SDK для браузера JavaScript, который включает в себя все необходимые плагины для настройки инструментов в различных аспектах веб-приложения. К ним относятся такие аспекты, как загрузка документов, взаимодействие с пользователем, отслеживание ошибок и HTTP-запросы.

Мы сделаем это, используя OpenTelemetry, универсальную среду наблюдения, предназначенную для упрощения сбора данных телеметрии. OpenTelemetry использует концепцию Traces, которая инкапсулирует коллекцию связанных промежутков.

Чтобы следовать вместе со мной, установите начальные пакеты:

npm install @opentelemetry/sdk-trace-web @opentelemetry/instrumentation @opentelemetry/sdk-trace-web @opentelemetry/exporter-trace-otlp-http @opentelemetry/instrumentation-fetch

Пользовательские инструменты

Начнем с реализации пользовательского fetch instrument:

import {
  FetchInstrumentation,
  FetchInstrumentationConfig,
} from '@opentelemetry/instrumentation-fetch';

export class CustomFetchInstrumentation extends FetchInstrumentation {
  constructor(config: FetchInstrumentationConfig) {
    config.applyCustomAttributesOnSpan = (span, request, result) => {
      // Add logic
      const { status } = result;

      if (status && status >= 400 && status < 500) {
        span.setAttribute('isClientError', 'true');
      }
    };

    super(config);
  }
}

Здесь мы расширяем FetchInstrumentation, чтобы получить доступ к данным по умолчанию, таким как URL, метод и статус. Используя метод applyCustomAttributesOnSpan, мы можем ввести наши собственные атрибуты. Подобные стратегии можно использовать для создания других индивидуальных инструментов.

export const INSTRUMENTATIONS = [
{
    Instrument: CustomFetchInstrumentation,
    confKey: 'fetch',
  },
  {
    Instrument: CustomDocumentInstrumentation,
    confKey: 'document',
  },
  {
    Instrument: CustomXHRInstrumentation,
    confKey: 'xhr',
  },
  {
    Instrument: CustomInteractionsInstrumentation,
    confKey: 'interactions',
  },
] as const;

Создание нашей инфраструктуры SDK

После успешной разработки желаемых инструментов мы переходим к определению ключевых интерфейсов:

interface BrowserSDKInstrumentations {
  document?: boolean;
  fetch?: boolean;
  xhr?: boolean;
  interactions?: boolean;
  // ...
}

export interface BrowserSdkConfig {
  application: string;
  version: string;
  environment: string;
  instrumentations: BrowserSDKInstrumentations;
  ignoreUrls?: Array<string | RegExp>;
  // ...
}

export interface BrowserSDKType {
  init: (options: BrowserSdkConfig) => void;
  // ...
}

Используя эти интерфейсы, у нас есть возможность создать объект BrowserSDK, который будет служить интерфейсом разработчика для интеграции SDK.

Интеграция инструментов и отправка трассировок

Наш следующий шаг предполагает подключение соответствующих инструментов к Browser SDK, чтобы инициировать создание трассировки определенных событий. Мы также будем использовать процессоры, предназначенные для манипулирования данными перед передачей, используя экспортер для отправки данных на наш сервер.

import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { WebTracerProvider} from '@opentelemetry/sdk-trace-web';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { BrowserSDKType } from "./types";

export const BrowserSDK: BrowserSDKType = {
  init: function (options) {
    // Initiate instrumentations based on options.
    const instrumentations = INSTRUMENTATIONS.filter(
      ({confKey}) => options?.instrumentations?.[confKey]
    ).map(({Instrument}) => (new Instrument({enabled: true, ...options})));

    const tracerProvider = new WebTracerProvider();

    const {application, version, environment} = options;

    // Attributes to be added to each span 
    tracerProvider.addSpanProcessor({
      forceFlush: () => Promise.resolve(),
      onEnd: () => {},
      shutdown: () => Promise.resolve(),
      onStart: (span: Span) => {
        span.setAttribute('application', application);
        span.setAttribute('version', version);
        span.setAttribute('environment', environment);
      },
    });

    // Add a Batch Span Processor to send data to a backend. 
    tracerProvider.addSpanProcessor(
      new BatchSpanProcessor(
        new OTLPTraceExporter({
          url: 'your-backend-url',
        })
      )
    );
    
    registerInstrumentations({
      tracerProvider,
      instrumentations,
    });
  }
}

Как это использовать

Чтобы использовать SDK для браузеров, позвоните BrowserSDK.init(options) в ближайшее время после загрузки страницы. Это приведет к инициализации SDK на основе предоставленных вами параметров.

BrowserSDK.init({
  instrumentations: {
    fetch: true,
    document: true,
    xhr: false
  },
  application: 'my-app',
  version: '1.0.2',
  environment: 'production'
})

Подведение итогов

Поздравляем! Вы успешно создали свой собственный браузерный SDK. Это достижение представляет собой лишь основу надежного SDK, который вы можете создать, используя ресурсы, предлагаемые OpenTelemetry.

В следующих статьях мы углубимся в создание инструментов ошибок, создание пользовательских экспортеров и другие сложные темы. Оставайтесь с нами, чтобы получить больше информации!

Следуйте за мной на LinkdIn, чтобы узнать больше.