README.md
1## Tracing Driver
2
3An experimental tracing backend that supports extremely low overhead tracing for JVM and Android
4apps; with the goal of supporting more platforms supported by the Kotlin Multiplatform ecosystem.
5
6The traces are captured using standard trace format defined by
7[Perfetto](https://perfetto.dev/docs/reference/trace-packet-proto). All tools that consume
8perfetto traces can continue being used. [ui.perfetto.dev](https://ui.perfetto.dev) can be used
9to visualize traces. Tools like
10[TraceProcessor](https://perfetto.dev/docs/analysis/trace-processor-python) can be used for
11analysing traces.
12
13## Usage
14
15To start recording traces, you need to create an instance of a
16[`TraceDriver`](src/commonMain/kotlin/androidx/tracing/driver/TraceDriver.kt).
17
18```kotlin
19val driver = TraceDriver(
20 // The trace sink. Determines where traces are stored.
21 // The library provides an implementation to a tracing sink out of the box.
22 // You can also write your own implementation of a TraceSink.
23 sink = JvmTraceSink(sequenceId = 1, baseDir = File("/path/to/trace/directory")),
24 // If injecting an instance of Driver, setting this to `false` means that no traces will be
25 // emitted to the sink. You don't have to change all the call sites where traces are captured.
26 isEnabled = true
27)
28```
29
30The `TraceDriver` provides a `context` which is of type
31[`TraceContext`](src/commonMain/kotlin/androidx/tracing/driver/TraceContext.kt).
32
33### Trace Context
34
35The `TraceContext` provides a way to create process and thread tracks. For more context on what
36tracks are, please refer
37to [the documentation](https://perfetto.dev/docs/instrumentation/track-events#tracks).
38
39### Process Tracks
40
41To create a [ProcessTrack](src/commonMain/kotlin/androidx/tracing/driver/ProcessTrack.kt) you can
42use the following API:
43
44```kotlin
45// driver.ProcessTrack(...) is an alias for driver.context.ProcessTrack(...)
46val process = driver.context.getOrCreateProcessTrack(
47 // The process id
48 id = 1,
49 // The name of the process
50 name = "processName"
51)
52```
53
54### Thread Tracks
55
56To create a [ThreadTrack](src/commonMain/kotlin/androidx/tracing/driver/ThreadTrack.kt), you can
57use a `ProcessTrack` instance :
58
59```kotlin
60val threadTrack = process.getOrCreateThreadTrack(
61 // The thread id
62 id = 10,
63 // The name of the thread
64 name = "threadName"
65)
66```
67
68### Tracing
69
70Once you have a track that you want to attach traces to, you can do:
71
72#### Basic
73
74```kotlin
75track.trace("traceSectionName") {
76 // The code that is being instrumented
77 doSomethingExpensive()
78}
79```
80
81#### Context Propagation
82
83The library also provides an implementation for tracing APIs that make use of Kotlin Coroutines
84to propagate the tracing context across multiple coroutines.
85
86```kotlin
87track.traceFlow("traceSectionName") {
88 // suspend block
89 // propagates flowId to inner coroutines automatically to do context propagation.
90}
91```
92
93For e.g.
94
95```kotlin
96suspend fun ProcessTrack.forkJoin(input: List<Int>) {
97 coroutineScope {
98 val batches = input.chunked(CHUNK_SIZE)
99 val jobs = mutableListOf<Deferred<List<Int>>()
100 batches.forEachIndexed { index, batch ->
101 jobs += async {
102 traceFlow("batch-$index") { fork(batch) }
103 }
104 }
105 val results = jobs.awaitAll()
106 return traceFlow("merge") {
107 merge(results)
108 }
109 }
110}
111```
112
113
114
115#### Counters
116
117You can also create tracks that emit counters as metrics. To create a counter you can use:
118
119```kotlin
120// The name of the counter.
121val counter = process.getOrCreateCounterTrack("MemoryUsage")
122```
123
124To emit metrics you can:
125
126```kotlin
127counter.setCounter(longValue)
128// Or
129counter.setCounter(doubleValue)
130```
131
132
133
134For an end to end tracing example app, look at
135[`TracingDemoTest.kt`](src/jvmTest/kotlin/androidx/tracing/driver/TracingDemoTest.kt).
136
137### Flushing Traces
138
139Traces are flushed to the sink asynchronously. To force a flush, you can always call `context.flush()`.
140
141Prior to termination of the program, call `traceContext.close()` to finalize all traces to the sink.
142(A [TraceContext](src/commonMain/kotlin/androidx/tracing/driver/TraceContext.kt) is a `Closeable`).
143