You might be inclined to wrap every function call in a span, send every action the user sends as an event, log every network request, …. Basically, track everything your app does and send it to Grafana. You’ll basically be able to debug everything everywhere all at once pun intended. :]
As much as this will be useful, this will get expensive quickly as you get more users. All telemetry solutions have limits to their free tiers, and paid plans are priced according to the amount of data. So the more data you send, the more value you get, and the more money you’ll have to pay.
This brings the question. Is all the data needed all the time? The answer won’t be yes.
You’ll want to monitor the overall health of your app to make sure main operations are working as expected. When something fails in the app, you add more information on what failed. More granular details when you’re investigating a problem.
The proposed idea is to implement all the tracing you want in the app, but have a configuration in your app that controls what to send and what not.
Say there are 4 levels, Add this enum in Common.swift:
public enum LoggingLevel: Int, Comparable {
public static func < (lhs: LoggingLevel, rhs: LoggingLevel) -> Bool {
lhs.rawValue < rhs.rawValue
}
case none = 0
case basic = 1
case detailed = 2
case maximum = 3
}
And add a global property in the same file:
var currentLoggingLevel = LoggingLevel.maximum
Next, take sendLog() as an example. Add a parameter in the method for the logging level:
public func sendLog(
scope: String,
timestamp: Date = Date(),
message: String,
loggingLevel: LoggingLevel = .detailed,
span: SpanType? = nil
) {
guard currentLoggingLevel >= loggingLevel else { return }
// The rest of the method
.
.
.
}
The approach is to implement all the telemetry across your code with different threshold levels. The threshold is defined by the parameter passed in the method.
Those telemetry will only work when currentLoggingLevel is greater than or equal to that threshold.
As for spans, the guard statement would execute the operation closure directly without creating any spans if the configuration is below the threshold:
As for how to control the global property currentLoggingLevel is up to you. Any feature toggle or A/B testing strategy you have will work.
The final project for this lesson has loggingLevel defined for all your telemetry methods, and they have different thresholds across the app.
There are more than one way to control the verbosity level of your app. You can tweak the classes from this project and create OTel clients per feature, and control the logging level per feature.
What’s important to remember, more data is not necessarily great. You need to remember that its not one user that will be sending this data. It’ll be all your users. So consider the scale in your calculations.
See forum comments
This content was released on Oct 24 2025. The official support period is 6-months
from this date.
In this segment, you’ll update your APIs to control the level telemetry of details your app sends.
Download course materials from Github
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress,
bookmark, personalise your learner profile and more!
Previous: Spans or withSpan
Next: Personally Identifiable Information
All videos. All books.
One low price.
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.