Integrating OpenTelemetry

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

In the previous part, you created a new account on Grafana and you created your own stack where you can find the dashboards and visualizations for all the traces and metrics you’ll send from your app.

To get started, open the sample project in the starter folder. It’s a mobile app that lets you search the Metropolitan Museum of Art with any keyword and lists the results on screen.

Start by adding OpenTelemetry’s SPM package from https://github.com/open-telemetry/opentelemetry-swift

Xcode will ask you to choose which targets to integrate in your project. Choose the following:

  • OpenTelemetryApi
  • OpenTelemetryProtocolExporter
  • OpenTelemetryProtocolExporterHTTP
  • OpenTelemetrySdk

In the project navigator, create a new folder under the project file and name it “Observability”, then create a new swift file names OTelMetrics.swift in that folder. Replace the code in the new file with the following:

import Foundation
import OpenTelemetryApi // 1
import OpenTelemetrySdk
import OpenTelemetryProtocolExporterCommon
import OpenTelemetryProtocolExporterHttp

public class OTelMetrics {
  public static var shared = OTelMetrics() // 2
  
  var grafanaExporter: OtlpHttpMetricExporter! // 3
  // 4
  let grafanaToken = "" // Set your Grafana token here
  let grafanaEndpoint = "" // Set your URL here
  
  private init() { // 5
  } 
}
  1. First you import the targets you added to the project through SPM.
  2. You’ll create a singleton instance of the class you just created OtelMetrics and you’ll be using the shared instance across the project.
  3. The OtlpHttpMetricExporter is the integration object that creates the connection between OpenTelemetry framework in your app and Grafana
  4. Set these properties to the token and URL you copied from Grafana in the previous section. Integration won’t work without them.
  5. Finally, an empty private init method. You’ll be filling it in now.

Add this to the private initializer:

let grafanaEndpoint = URL(string: "\(grafanaEndpoint)/v1/metrics")! // 1
let grafanaHeaders = OtlpConfiguration(headers: [("Authorization", "Basic \(grafanaToken)")], exportAsJson: true) // 2
grafanaExporter = OtlpHttpMetricExporter(endpoint: grafanaEndpoint, config: grafanaHeaders) // 3

OpenTelemetry.registerMeterProvider( // 4
  meterProvider: MeterProviderSdk.builder()
    .registerView(selector: InstrumentSelector.builder().setInstrument(name: ".*").build(), view: View.builder().build())
    .registerMetricReader(reader: PeriodicMetricReaderBuilder(exporter: grafanaExporter).setInterval(timeInterval: 5).build())
    .build()
)
  1. Create a URL instance with the the Grafana server.
  2. Create the configuration Grafana needs to authenticate the connection against your Grafana stack that you created. Its a tuple of strings, and specified the data to be sent as JSON.
  3. Create an instance of OtlpHttpMetricExporter using the URL and the configuration.
  4. Register the meter provider which consists of two parts:
    • View uses the basic settings to define which metrics to observe.
    • Metric Reader which you’ll set up as a periodic reader that uses the exporter you configured for Grafana, and defines the interval at which the meter values are synchronized.

This concludes configuring the framework for sending metrics to Grafana. To start sending the metrics, add this new method to OtelMetrics.swift:

public func sendGauge(  // 1
  metricsGroup: String,
  name: String,
  value: Double,
  attributes: [String: AttributeValue] = [:]
) {
  let openTelemetry = OpenTelemetry.instance  // 2
  
  let meter = openTelemetry.meterProvider.meterBuilder(name: metricsGroup).build()  // 3
  
  var gauge = meter.gaugeBuilder(name: name).build()  // 4
  
  gauge.record(value: value, attributes: attributes)  // 5
}
  1. The new method takes 2 strings, a double which defines the value of the gauge, and an optional dictionary to include in the gauge properties.
  2. First, you get the current instance of OpenTelemetry.
  3. Create an instance of a meter with the name of metricsGroup.
  4. Create the gauge itself with the name you specified.
  5. Finally, set the value to the gauge along with the attributes.

Next, add this method right after the previous one:

public class func sendGauge(
  metricsGroup: String,
  name: String,
  value: Double,
  attributes: [String: AttributeValue] = [:]
) {
  shared.sendGauge(metricsGroup: metricsGroup, name: name, value: value, attributes: attributes)
}

This overload provides a class-level convenience method that delegates the work to the shared instance, so you don’t need to instantiate the class manually when sending a gauge.

This all you need to send metrics to Grafana through OpenTelemetry framework. To try it out, go to TheMetStore.swift and add the following code inside fetchObjects(for:), at the end of the if statement.

print("got \(objects.count) objects")
// Add this
OTelMetrics.sendGauge(
  metricsGroup: "TheMet-Metrics",
  name: "ObjectsCount",
  value: Double(objects.count)
)

This sends the number of objects saved in the store with each query. Build and run the app, then search for a few queries.

Open your Grafana dashboard, from the side menu, expand “Drilldown” then select “Metrics”.

It can take a couple of mins before the graph show values. refresh the graph a couple of times if you don’t see any values. Once they appear, it would look similar to this:

The graph will show the average number of objects stored in TheMetStore.objects at any moment for all active users.

Don’t worry too much about the type of metric you’re sending right now. Over this module, you’ll learn about different kinds of data and how they can be visualized on Grafana.

See forum comments
Download course materials from Github
Previous: Getting Started Next: Conclusion