Events

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

Starting a search with a keyword represents an event, while receiving the results represents another event. You have a span that represents both of those 2 moments. But in many cases you’ll want to mark a moment in time with something that happened with some data to give insight on what happened.

Another use for events is sending a one-time value where a gauge doesn’t fit, since gauges present a continuous value for the app. One-off values are like when the app goes to the background or foreground, opens a screen, or receives a value from a server or a different framework. These are things related to a single moment in time with a certain value, and not about time duration.

OpenTelemetry treats Events almost the same as logs. The API has slight differences between each to focus on whats important to define an event, and for a log.

Go to OTelLogs.swift and add the following at the end of the class:

public func sendEvent(
  scope: String,
  eventName: String,
  data: [String: AttributeValue],
  message: String = "",
  span: (any Span)? = nil
) {
  let openTelemetry = OpenTelemetry.instance
  let otelLogger = openTelemetry.loggerProvider.loggerBuilder(instrumentationScopeName: scope).setEventDomain("Device") .build()
  let event = otelLogger.eventBuilder(name: eventName)
    .setData(data)
    .setBody(.string(message))
  if let span {
    _ = event.setSpanContext(span.context)
  }
  event.emit()
  _ = grafanaExporter.flush()
}

public class func sendEvent(
  scope: String,
  eventName: String,
  data: [String: AttributeValue],
  message: String = "",
  span: (any Span)? = nil
) {
  shared.sendEvent(
    scope: scope,
    eventName: eventName,
    data: data,
    message: message,
    span: span)
}

The main difference in sendEvent() is that an event should have a name and attributes. The message isn’t very important but there is nothing preventing you from adding one if you feel it’s valuable.

You’re probably familiar with Business Analytics platforms like Google Analytics for example. Those business events and your OpenTelemetry events are not much different. The key difference is that those analytics platforms are tailored for business use-cases and have a lot of convenient tooling and ready dashboards to give business insights on sales, user retention, app engagement, … etc. You can do the same ofc with OpenTelemetry and Grafana, but you’d be spending too much time to re-invent the wheel. :]

Go to TheMetStore.swift and add the following right after sending the OTel Log:

OTelLogs.sendEvent(
  scope: "TheMet-Logs",
  eventName: "objects_fetched",
  data: ["value" : AttributeValue.int(objects.count)])

The AttributeValue is an enum to help maintain the data types of attribute values during serialization. It’s defined in OpenTelemetryApi. Make sure to add the import for OpenTelemetryApi to be able to use this AttributeValue.

Build and run the app. Search a few times to send a few events.

Open your Grafana portal, and open the logs for “TheMet”

Events and Logs are together in 'Logs' dashboard for Grafana
Events and Logs are together in 'Logs' dashboard for Grafana

You’ll see the events and logs all together.

Grafana won’t create a graph on its own for the values you’re sending in those event because it doesn’t know about them. Why not create a custom dashboard for this?

From the left menu on Grafana, open “Dashboards”, then choose “New dashboard” from the “New” dropdown in the top right corner

Add new dashboard from the 'New' button
Add new dashboard from the 'New' button

Select “Add visualization”, then choose “grafanacloud-[YOUR_PORTAL_NAME]_logs” as the datasource.

Choosing the logs datasource for the new dashboard
Choosing the logs datasource for the new dashboard

In the bottom half, in “Label filters” choose “service_name” as key field dropdown, and “TheMet” as the value from the dropdown. Press “Run query”

Run query for 'TheMet' service name
Run query for 'TheMet' service name

This will list all the logs coming from your app. You want to filter out the events that are named “objects_fetched” and create a visual graph from them.

In the middle of the screen, select the second tab “Transformations” then add the first transformation of type “Extract fields”

Add 'Extract fields' transformation
Add 'Extract fields' transformation

Set “labels” as the source, and “JSON” as the format

Setup the fields for the 'Extract fields' transformation
Setup the fields for the 'Extract fields' transformation

This allows Grafana to extract all the custom values present in the log.

Then add another transformation of type “Convert field type”. Set field to “event_data_value” from the field dropdown, and “Number” for the type.

Setup the fields for the 'Convert field type' transformation
Setup the fields for the 'Convert field type' transformation

Go back to the “Queries” tab, and change the view to “Code” instead of “Builder” besides the “Run qurey” button. Set the query to {service_name="TheMet"} | event_name="objects_fetched"

Set the query to search for event name 'objects_fetched'
Set the query to search for event name 'objects_fetched'

Once you see the correct filtered log entries, choose “Time series” visualization option from the search field on the right of the screen. Change the view on the top to graph by turning off “Table view” switch.

Graph representation for the logs
Graph representation for the logs

This will automatically convert the event entries to a visual representation.

Grafana recognized which values to graph because it found a “Number” type in one of the values which you did through the second transformation.

You might be thinking, If Grafana is treating logs and events almost the same way then what’s the difference?

The answer is not necessarily technical. Logs and events can both share the same technical data structure and have their similarities.

Logs are meant to describe the state of the system when something happens. A crash log is clear enough that the event is a crash, but what was happening in the app is what is important. As for an Event, it focuses on providing data for the event itself, like a purchase event. It doesn’t matter what the state of the application is, how much memory, how many screens, the battery state, the network state, … etc. All this is not important. What is important is what item the user purchased, the category, price, … etc. And events need to be structured because they provide a lot of information when you put them together and they are meant to be processed in quantity. However, logs can be very valuable as individual entries.

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