Skip to content

OTLPTraceExporter from exporter-trace-otlp-http exporting traces Base64 encoded in React Native #5178

@DanielOnramp

Description

@DanielOnramp

What happened?

Steps to Reproduce

Expected Result

Traces exported to collector endpoint in JSON format

Actual Result

Traces are being Base64 encoded via the OTLPTraceExporter, resulting in 400 response as endpoint expects JSON

Additional Details

When recreating this implementation of @optentelemetry in a React web app, traces are exported successfully in JSON format.

@opentelemetry DiagConsoleLogger indicates "stack":"ReferenceError: Property 'TextEncoder' doesn't exist\n at serializeRequest.

Importing the text-encoding polyfill clears this error and allows traces to be sent, but in the wrong format.

OpenTelemetry Setup Code

import 'text-encoding'; // Import the polyfill
import {
  CompositePropagator,
  W3CBaggagePropagator,
  W3CTraceContextPropagator,
} from '@opentelemetry/core';
import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
import {
  SimpleSpanProcessor,
  ConsoleSpanExporter,
} from '@opentelemetry/sdk-trace-base';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web';
import { Resource } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { DiagConsoleLogger, DiagLogLevel, diag } from '@opentelemetry/api';
import { useEffect, useState } from 'react';
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);

const GRAFANA_OTLP_ENDPOINT = '<my-trace-collector-url>`;
const SERVICE_NAME = 'my-react-native-app`;


const Tracer = async () => {
  const resource = new Resource({
    [ATTR_SERVICE_NAME]: SERVICE_NAME,
  });
  const provider = new WebTracerProvider({ resource });

  provider.addSpanProcessor(
    new SimpleSpanProcessor(
      new OTLPTraceExporter({
        url: GRAFANA_OTLP_ENDPOINT,
      })
    )
  );


  provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));

  provider.register({
    propagator: new CompositePropagator({
      propagators: [
        new W3CBaggagePropagator(),
        new W3CTraceContextPropagator(),
      ],
    }),
  });

  registerInstrumentations({
    tracerProvider: provider,
    instrumentations: [
      getWebAutoInstrumentations({
        '@opentelemetry/instrumentation-user-interaction': { enabled: false },
        '@opentelemetry/instrumentation-document-load': { enabled: false },
        '@opentelemetry/instrumentation-fetch': {
          propagateTraceHeaderCorsUrls: /.*/,
          clearTimingResources: false,
        },
      }),
    ],
  });
};

export interface TracerResult {
  loaded: boolean;
}

export const useTracer = (): TracerResult => {
  const [loaded, setLoaded] = useState<boolean>(false);

  useEffect(() => {
    if (!loaded) {
      Tracer()
        .catch(() => console.warn('failed to setup tracer'))
        .finally(() => setLoaded(true));
    }
  }, [loaded]);

  return {
    loaded,
  };
};

package.json

{
  "name": "my-app",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    ....
  },
  "dependencies": {
    "@apollo/client": "3.5.10",
    "@eva-design/eva": "^2.2.0",
    "@expo/react-native-action-sheet": "^4.0.1",
    "@gorhom/bottom-sheet": "^4.6.0",
    "@grafana/faro-react": "^1.11.0",
    "@grafana/faro-web-tracing": "^1.11.0",
    "@opentelemetry/api": "^1.9.0",
    "@opentelemetry/auto-instrumentations-web": "^0.42.0",
    "@opentelemetry/exporter-collector": "^0.25.0",
    "@opentelemetry/exporter-trace-otlp-http": "^0.54.0",
    "@opentelemetry/instrumentation": "^0.54.0",
    "@opentelemetry/sdk-trace-base": "^1.27.0",
    "@opentelemetry/sdk-trace-web": "^1.27.0",
    "@react-native-async-storage/async-storage": "1.21.0",
    "@react-native-community/checkbox": "^0.5.17",
    "@react-native-community/netinfo": "11.1.0",
    "@react-navigation/bottom-tabs": "^6.2.0",
    "@react-navigation/native": "^6.0.2",
    "@react-navigation/native-stack": "^6.1.0",
    "@sentry/react-native": "~5.33.1",
    "@ui-kitten/components": "^5.1.1",
    "@ui-kitten/eva-icons": "^5.1.1",
    "@ui-kitten/template-ts": "^5.1.2",
    "date-fns": "^2.30.0",
    "expo": "~50.0.19",
    "expo-application": "~5.8.4",
    "expo-auth-session": "~5.4.0",
    "expo-checkbox": "^3.0.0",
    "expo-clipboard": "~5.0.1",
    "expo-constants": "~15.4.6",
    "expo-crypto": "~12.8.1",
    "expo-dev-client": "~3.3.12",
    "expo-device": "~5.9.4",
    "expo-local-authentication": "~13.8.0",
    "expo-location": "~16.5.5",
    "expo-notifications": "~0.27.8",
    "expo-splash-screen": "~0.26.5",
    "expo-status-bar": "~1.11.1",
    "expo-updates": "~0.24.13",
    "formik": "^2.4.5",
    "geolib": "^3.3.4",
    "graphql": "^16.3.0",
    "graphql-ws": "^5.11.2",
    "jwt-decode": "^3.1.2",
    "lodash": "^4.17.21",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-native": "0.73.6",
    "react-native-animatable": "^1.4.0",
    "react-native-circular-progress-indicator": "^4.4.2",
    "react-native-collapsible": "^1.6.1",
    "react-native-error-boundary": "^1.1.13",
    "react-native-gesture-handler": "~2.14.0",
    "react-native-google-places-autocomplete": "^2.5.6",
    "react-native-keyboard-aware-scroll-view": "^0.9.5",
    "react-native-loading-spinner-overlay": "^2.0.0",
    "react-native-map-link": "^2.11.4",
    "react-native-maps": "1.10.0",
    "react-native-maps-directions": "^1.9.0",
    "react-native-modal": "^13.0.1",
    "react-native-paper": "^4.11.2",
    "react-native-qrcode-svg": "^6.3.0",
    "react-native-reanimated": "~3.6.2",
    "react-native-safe-area-context": "4.8.2",
    "react-native-safearea-height": "^1.0.6",
    "react-native-screens": "~3.29.0",
    "react-native-svg": "14.1.0",
    "react-native-svg-animated-linear-gradient": "^0.4.0",
    "react-native-toast-message": "^2.1.5",
    "react-native-turbo-mock-location-detector": "^2.3.1",
    "react-native-vector-icons": "^9.0.0",
    "sentry-expo": "~7.2.0",
    "styled-components": "^5.3.1",
    "text-encoding": "^0.7.0",
    "yup": "^0.32.11"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@babel/runtime": "^7.15.3",
    "@react-native-community/eslint-config": "^3.2.0",
    "@testing-library/jest-native": "^5.4.2",
    "@testing-library/react-native": "^12.2.2",
    "@types/jest": "^29.5.3",
    "@types/react-test-renderer": "^18.0.0",
    "@types/styled-components": "^5.1.14",
    "@types/styled-components-react-native": "^5.1.1",
    "@typescript-eslint/eslint-plugin": "^6.7.5",
    "@typescript-eslint/parser": "^6.7.5",
    "babel-jest": "^26.6.3",
    "babel-plugin-module-resolver": "^4.1.0",
    "eslint": "^8.51.0",
    "eslint-plugin-react": "^7.32.2",
    "husky": "^8.0.3",
    "jest": "^29.6.2",
    "lint-staged": "^13.1.2",
    "metro-react-native-babel-preset": "^0.66.2",
    "patch-package": "^8.0.0",
    "prettier": "^2.8.7",
    "react-devtools": "^5.0.0",
    "react-test-renderer": "18.2.0",
    "reactotron-react-native": "^5.0.3",
    "typescript": "^5.3.0"
  },
  "resolutions": {
    "@types/react": "^18"
  },
  "jest": {
    "preset": "react-native",
    "setupFilesAfterEnv": [
      "@testing-library/jest-native/extend-expect"
    ],
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx",
      "json",
      "node"
    ]
  },
  "lint-staged": {
    "src/**/*.{ts,tsx}": [
      "prettier --write",
      "eslint --fix"
    ]
  }
}

Relevant log output

## Traces being created on the client, 
DEBUG  items to be sent [{"_attributeValueLengthLimit": Infinity, "_droppedAttributesCount": 0, "_droppedEventsCount": 0, "_droppedLinksCount": 0, "_duration": [1, 172728833], "_ended": true, "_performanceOffset": NaN, "_performanceStartTime": 345362964.276208, "_spanContext": {"spanId": "9bddc617a3821ea9", "traceFlags": 1, "traceId": "a31d5b512aa2d966ecfd093da35d11f8", "traceState": undefined}, "_spanLimits": {"attributeCountLimit": 128, "attributePerEventCountLimit": 128, "attributePerLinkCountLimit": 128, "attributeValueLengthLimit": Infinity, "eventCountLimit": 128, "linkCountLimit": 128}, "_spanProcessor": {"_spanProcessors": [Array]}, "_startTimeProvided": false, "attributes": {"example-attribute": "example-value"}, "endTime": [1732027524, 681728833], "events": [], "instrumentationLibrary": {"name": "default", "schemaUrl": undefined, "version": undefined}, "kind": 0, "links": [], "name": "example-span", "parentSpanId": undefined, "resource": {"_asyncAttributesPromise": undefined, "_attributes": [Object], "_syncAttributes": [Object], "asyncAttributesPending": false}, "startTime": [1732027523, 509000000], "status": {"code": 0}}]



## Request payload in XHR  (base64 encoded)
eyJyZXNvdXJjZVNwYW5zIjpbeyJyZXNvdXJjZSI6eyJhdHRyaWJ1dGVzIjpbeyJrZXkiOiJzZXJ2aWNlLm5hbWUiLCJ2YWx1ZSI6eyJzdHJpbmdWYWx1ZSI6InJlYWN0LW5hdGl2ZS1mdWVscGF5In19LHsia2V5IjoidGVsZW1ldHJ5LnNkay5sYW5ndWFnZSIsInZhbHVlIjp7InN0cmluZ1ZhbHVlIjoid2VianMifX0seyJrZXkiOiJ0ZWxlbWV0cnkuc2RrLm5hbWUiLCJ2YWx1ZSI6eyJzdHJpbmdWYWx1ZSI6Im9wZW50ZWxlbWV0cnkifX0seyJrZXkiOiJ0ZWxlbWV0cnkuc2RrLnZlcnNpb24iLCJ2YWx1ZSI6eyJzdHJpbmdWYWx1ZSI6IjEuMjcuMCJ9fV0sImRyb3BwZWRBdHRyaWJ1dGVzQ291bnQiOjB9LCJzY29wZVNwYW5zIjpbeyJzY29wZSI6eyJuYW1lIjoiZGVmYXVsdCJ9LCJzcGFucyI6W3sidHJhY2VJZCI6IjdmNWZlMzc5YzBkNzYzOTE1MzY4MWU4NzQ2MmJhMGFmIiwic3BhbklkIjoiN2U0MzI1NTZlZDM2N2M4NiIsIm5hbWUiOiJleGFtcGxlLXNwYW4iLCJraW5kIjoxLCJzdGFydFRpbWVVbml4TmFubyI6IjE3MzIwMjc1OTM0MjUwMDAwMDAiLCJlbmRUaW1lVW5peE5hbm8iOiIxNzMyMDI3NTk0NjExNzc3NzA5IiwiYXR0cmlidXRlcyI6W3sia2V5IjoiZXhhbXBsZS1hdHRyaWJ1dGUiLCJ2YWx1ZSI6eyJzdHJpbmdWYWx1ZSI6ImV4YW1wbGUtdmFsdWUifX1dLCJkcm9wcGVkQXR0cmlidXRlc0NvdW50IjowLCJldmVudHMiOltdLCJkcm9wcGVkRXZlbnRzQ291bnQiOjAsInN0YXR1cyI6eyJjb2RlIjowfSwibGlua3MiOltdLCJkcm9wcGVkTGlua3NDb3VudCI6MH1dfV19XX0=

Operating System and Version

macOS 15.1

Runtime and Version

react-native 0.73.6
expo ~50.0.19
iPhone 16 Pro Simulator iOS 18.0

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions