JLPluginOpenTelemetry

A Jasonelle plugin that wraps the OpenTelemetry SDK to track application metrics.

Overview

JLPluginOpenTelemetry bridges the OpenTelemetry Swift API to JavaScript. It records counters and histograms on any meter, so metrics raised in the web view reach whatever exporter the app has configured.

Structure

File Role

Plugin.swift

Native side – resolves a Meter from OpenTelemetry.instance.meterProvider and records the requested metric.

Plugin.js

JavaScript side – registers the plugin on window.jasonelle.plugins.opentelemetry.

How it works

  1. The plugin is injected into the web view on page load and registers itself on window.jasonelle.plugins.opentelemetry.

  2. counter(name, value, meterName) and histogram(name, value, meterName) post a message to native and return a promise.

  3. The call is routed to Plugin.swift handle_call(callbackId:args:respond:), which reads action and dispatches to the requested metric action.

  4. The plugin gets a meter, builds the instrument, records the value, and resolves the promise.

await window.jasonelle.plugins.opentelemetry.counter("button_clicks", 1);
await window.jasonelle.plugins.opentelemetry.histogram("load_time_ms", 124.5);

The same call can be made without the JavaScript wrapper, using window.jasonelle.post to send the arguments straight to handle_call. The first argument is the plugin id, not the short name used to register it on window.jasonelle.plugins:

await window.jasonelle.post("com.jasonelle.plugins.opentelemetry", {
    action: "counter.add",
    name: "button_clicks",
    value: 1,
    meterName: "jasonelle.app.meter"
});

Arguments

Key Type Required Default Description

action

string

yes

–

counter.add or histogram.record.

name

string

yes

–

Instrument name, for example button_clicks.

value

number

yes

–

Value added to the counter, or recorded in the histogram.

meterName

string

no

jasonelle.app.meter

Meter the instrument is created on.

JavaScript numbers arrive in the message as NSNumber, so Plugin.swift coerces them to Int and Double. counter.add truncates value to a whole number, matching the LongCounter instrument on the Android plugin.

Response

{
  "status": "ok",
  "callbackId": "call_1",
  "success": true
}

success reports that the bridge call was accepted, not that a value reached the SDK. A missing or non-numeric name or value is dropped natively and the promise still resolves with success: true.

Errors

{
  "status": "error",
  "callbackId": "call_1",
  "error": "No action provided"
}
  • No action provided – the arguments carried no string action.

  • Unknown action <action> – action was neither counter.add nor histogram.record.

JLKernel.Plugin.reject defaults its status to "ok", so every reject call must pass status: "error" explicitly. Otherwise the promise rejects with a "status": "ok" payload the JavaScript client treats as a success.

SDK requirement

The app must register a MeterProvider before the first call. Without one the default is a no-op DefaultMeterProvider, every value is discarded and the promise still resolves with success: true.
OpenTelemetry.instance.meterProvider is read-only. Register a provider with OpenTelemetry.registerMeterProvider(meterProvider:), which takes any MeterProvider including a MeterProviderSdk built from OpenTelemetrySdk.
import OpenTelemetryApi
import OpenTelemetrySdk

let provider = MeterProviderSdk.builder()
  .setResource(Resource(attributes: ["service.name": .string("jasonelle-app")]))
  .registerMetricReader(metricReader) // e.g. a periodic reader over your exporter
  .build()

OpenTelemetry.registerMeterProvider(meterProvider: provider)

Register the provider in the Application module, before the web view loads the page that raises the first metric. The plugin links only OpenTelemetryApi, so MeterProviderSdk and any exporter are the app’s dependency to add.

Wiring

The plugin is a Swift Package consumer. project.pbxproj references opentelemetry-swift-core 2.6.0 and links its OpenTelemetryApi product, and the project is listed in Jasonelle.xcworkspace. Add both when creating a plugin that depends on an external package.

Tests

Eleven cases in JLPluginOpenTelemetryTests cover the exposed name and id, the null and empty argument rejects, both actions resolving, the silently dropped malformed arguments, the unknown action reject, the unhandled event, and the bundled JavaScript.

cd sources/xcode
task test -- JLPluginOpenTelemetryTests
the JLKernel.framework dependency resolves through BUILT_PRODUCTS_DIR, so the project only builds from Jasonelle.xcworkspace, never on its own with -project.

Reference

  • JLKernel.Plugin – the base class this plugin extends.

  • Plugin.js – the JavaScript client, byte-identical to the Android plugin.

  • OpenTelemetryApi from opentelemetry-swift-core 2.6.0, declared as a Swift Package dependency in project.pbxproj.