AWS Distro for OpenTelemetry

Manual Instrumentation for Traces and RUM Events with the Swift Agent

Manual Instrumentation for Traces and RUM Events with the Swift Agent

Introduction

The AWS Distro for OpenTelemetry (ADOT) Swift SDK can be installed onto any iOS application running on iOS 16+ to gather real user monitoring (RUM) telemetry data. The Swift SDK acts as a wrapper atop the OpenTelemetry (OTel) SDK to simplify the process of instrumenting applications. It is pre-configured for compatibility with AWS CloudWatch RUM but can also be used with any other tracing backend. Out of the box, it propagates traces using W3C Trace Context.

The Swift Agent is the recommended way to instrument most iOS applications for Traces and RUM events. For more information, refer to the documentation on auto-instrumentation.




Requirements

Currently, the Swift SDK is only officially supported on applications running on iOS 16 (or later). We do not have official out-of-the-box support for macOS, tvOS, watchOS, and visionOS at this time. Swift 5.9 (or later) is recommended to build the Agent into your application.




Installation

The ADOT Swift SDK is available to consume via Swift Package Manager (SPM). You should add the Swift SDK to your Package.swift :

1dependencies: [
2 .package(url: "https://github.com/aws-observability/aws-otel-swift.git", .upToNextMajor(from: "1.0.0"))
3]

Then, to start using the SDK, you will need to add AwsOpenTelemetryCore to target dependencies:

1targets: [
2 .target(
3 name: "<your app target>",
4 dependencies: [
5 .product(name: "AwsOpenTelemetryCore", package: "aws-otel-swift")
6 ]
7 )
8]

The AwsOpenTelemetryAgent dependency requires you to manually initialize the SDK in your application code. Next, we'll discuss how to initialize and configure the SDK.




Initializing the SDK in your application

In your AppDelegate , you must initialize the OTel SDK using the AwsOpenTelemetryRumBuilder:

1import AwsOpenTelemetryCore
2
3class AppDelegate: UIResponder, UIApplicationDelegate {
4 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
5 AwsOpenTelemetryRumBuilder.create(
6 // Incomplete configuration - the SDK can't export anywhere
7 config: AwsOpenTelemetryConfig()
8 )?.build()
9 return true
10 }
11}

This will initialize the OTel SDKs with the pre-configured suite of default instrumentations on your application. Next, you will configure the SDK to point the telemetry somewhere.




Configuring the SDK with AWS CloudWatch RUM (with resource-based policies)

ADOT Swift is pre-configured to work with AWS CloudWatch RUM. To export RUM telemetry to CloudWatch RUM, you will need to first create an app monitor with resource-based policies. Next, modify your code with the following:

1import AwsOpenTelemetryCore
2
3class AppDelegate: UIResponder, UIApplicationDelegate {
4 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
5 AwsOpenTelemetryRumBuilder.create(
6 config: AwsOpenTelemetryConfig(
7
8 // point telemetry to AWS RUM
9 aws: AwsConfig(
10 rumAppMonitorId: "<your app monitor id>",
11 region: "<your app monitor region>",
12
13 // optional, if you have a resource-based policy with an alias
14 alias: "<your rum alias>"
15 ),
16
17 // customize your OTel Resource
18 otelResourceAttributes: [
19 "service.name": "MyApplication",
20 "service.namespace": "MyTeam",
21 "service.version": "1.0.0",
22 "deployment.environment": "production"
23 ]
24 )
25 )?.build()
26 return true
27 }
28}

That's it! This is the minimum configuration to begin exporting RUM telemetry to CloudWatch RUM. From there, you can use CloudWatch RUM and CloudWatch Application Signals to monitor your application health and track long-term application performance against your business objectives.

Application Signals provides you with a unified, application-centric view of your applications, services, and dependencies, and helps you monitor and triage application health.

Get started with CloudWatch Application Signals

Use resource-based policies with CloudWatch RUM




Configuring the SDK with other OTLP endpoints

To export to a third-party OTLP endpoint that is not yet supported in the Swift SDK out of the box, you can use the exportOverride field to provide custom logs and traces endpoints:

1AwsOpenTelemetryRumBuilder.create(
2 config: AwsOpenTelemetryConfig(
3 aws: AwsConfig(
4 rumAppMonitorId: "<your app monitor id>",
5 region: "<your region>"
6 ),
7 exportOverride: AwsExportOverride(
8 logs: "http://localhost:4318/v1/logs",
9 traces: "http://localhost:4318/v1/traces"
10 ),
11 )
12)?.build()



Exporting with Sigv4 headers

To simplify the process of exporting telemetry via OTLP with Sigv4 signed requests, the Swift SDK ships with an optional AwsOpenTelemetryAuth library. You are responsible for sourcing your own credentials in a secure manner. An example implementation could look like:

1import AwsOpenTelemetryAuth
2import AwsOpenTelemetryCore
3
4class AppDelegate: UIResponder, UIApplicationDelegate {
5 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
6 // Create your own credentials provider
7 let customCredentialsProvider = YourCustomCredentialsProvider()
8
9 AwsOpenTelemetryRumBuilder.create(
10 config: AwsOpenTelemetryConfig(
11
12 // point telemetry to AWS RUM
13 aws: AwsConfig(
14 rumAppMonitorId: "<your app monitor id>",
15 region: "<your app monitor region>",
16
17 // optional, if you have a resource-based policy with an alias
18 alias: "<your rum alias>"
19 ),
20
21 // customize your OTel Resource
22 otelResourceAttributes: [
23 "service.name": "MyApplication",
24 "service.namespace": "MyTeam",
25 "service.version": "1.0.0",
26 "deployment.environment": "production"
27 ]
28 )
29 )?
30 .addSpanExporterCustomizer { _ in
31 try AwsSigV4SpanExporterBuilder()
32 .setRegion("us-east-1")
33 .setCredentialsProvider(customCredentialsProvider)
34 .build()
35 }
36 .addLogRecordExporterCustomizer { _ in
37 try AwsSigV4LogRecordExporterBuilder()
38 .setRegion("us-east-1")
39 .setCredentialsProvider(customCredentialsProvider)
40 .build()
41 }
42 .build()
43 return true
44 }
45}

NOTE: Vending your application with static credentials in a production environment carries inherent risk. One possible solution is to source your credentials from Amazon Cognito using the AWS SDK for Kotlin.




Advanced customization of the SDK

By default, the SDK enables all available telemetry types. You can selectively enable or disable specific telemetry types to control what RUM data is collected from your application.

1import AwsOpenTelemetryCore
2
3class AppDelegate: UIResponder, UIApplicationDelegate {
4 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
5
6 AwsOpenTelemetryRumBuilder.create(
7 config: AwsOpenTelemetryConfig(
8 aws: AwsConfig(
9 rumAppMonitorId: "your-app-monitor-id",
10 region: "us-east-1"
11 ),
12 otelResourceAttributes: [
13 "service.name": "MyApplication"
14 ],
15 telemetry: AwsTelemetryConfig(
16 startup: AwsTelemetryConfig.Feature(enabled: true), // App startup monitoring
17 sessionEvents: AwsTelemetryConfig.Feature(enabled: true), // Session start/end events
18 crash: AwsTelemetryConfig.Feature(enabled: true), // Crash reporting
19 hang: AwsTelemetryConfig.Feature(enabled: true), // ANR/hang detection
20 network: AwsTelemetryConfig.Feature(enabled: true), // Network instrumentation
21 view: AwsTelemetryConfig.Feature(enabled: true) // UIKit/SwiftUI view spans
22 ),
23 sessionSampleRate: 0.1 // sample 10% of sessions
24 )
25 )?.build()
26
27 return true
28 }
29}

For more advanced configuration options, refer to the ADOT Swift GitHub repository.