Skip to content

Commit b77f2cd

Browse files
authored
feat: File I/O instrumentation (#4575)
1 parent 5bf7d62 commit b77f2cd

File tree

7 files changed

+343
-1
lines changed

7 files changed

+343
-1
lines changed

src/includes/getting-started-primer/android.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ The SDK builds a crash report that persists to disk and tries to send the report
3030
- Slow and frozen frames measurements with [Automatic Instrumentation](/platforms/android/performance/instrumentation/automatic-instrumentation/#slow-and-frozen-frames)
3131
- OkHttp request spans with [OkHttp Integration](/platforms/android/configuration/integrations/okhttp/)
3232
- SQLite and Room query spans with [Room and SQLite Integration](/platforms/android/configuration/integrations/room-and-sqlite/)
33+
- File I/O spans with [File I/O Integration](/platforms/android/configuration/integrations/file-io/)
3334
- Apollo request spans with [Apollo Integration](/platforms/android/configuration/integrations/apollo/)
3435
- Distributed tracing through [OkHttp](/platforms/android/configuration/integrations/okhttp/) and [Apollo](/platforms/android/configuration/integrations/apollo/) integrations
3536
- [Application Not Responding (ANR)](/platforms/android/configuration/app-not-respond/) reported if the application is blocked for more than five seconds
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
To instrument `FileInputStream`/`FileOutputStream` the SDK provides drop-in replacements such as `SentryFileInputStream`/`SentryFileOutputStream`.
2+
3+
_Old_:
4+
```java
5+
import java.io.File;
6+
import java.io.FileInputStream;
7+
import java.io.FileOutputStream;
8+
9+
File file1 = new File("file1.txt");
10+
File file2 = new File("file2.txt");
11+
try (FileInputStream fis = new FileInputStream(file1)) {
12+
byte[] buffer = new byte[1024];
13+
try (FileOutputStream fos = FileOutputStream(file2)) {
14+
int read;
15+
while (true) {
16+
read = fis.read(buffer);
17+
if (read == -1) {
18+
break;
19+
}
20+
fos.write(buffer, 0, read);
21+
}
22+
}
23+
}
24+
```
25+
26+
```kotlin
27+
import java.io.File
28+
import java.io.FileInputStream
29+
import java.io.FileOutputStream
30+
31+
val file1 = File("file1.txt")
32+
val file2 = File("file2.txt")
33+
FileInputStream(file1).use { FileOutputStream(file2).write(it.readBytes()) }
34+
```
35+
36+
_New_:
37+
```java
38+
import io.sentry.instrumentation.file.SentryFileInputStream;
39+
import io.sentry.instrumentation.file.SentryFileOutputStream;
40+
import java.io.File;
41+
import java.io.FileInputStream;
42+
import java.io.FileOutputStream;
43+
44+
File file1 = new File("file1.txt");
45+
File file2 = new File("file2.txt");
46+
try (FileInputStream fis = new SentryFileInputStream(file1)) {
47+
byte[] buffer = new byte[1024];
48+
try (FileOutputStream fos = SentryFileOutputStream(file2)) {
49+
int read;
50+
while (true) {
51+
read = fis.read(buffer);
52+
if (read == -1) {
53+
break;
54+
}
55+
fos.write(buffer, 0, read);
56+
}
57+
}
58+
}
59+
```
60+
61+
```kotlin
62+
import io.sentry.instrumentation.file.SentryFileInputStream
63+
import io.sentry.instrumentation.file.SentryFileOutputStream
64+
import java.io.File
65+
66+
val file1 = File("file1.txt")
67+
val file2 = File("file2.txt")
68+
SentryFileInputStream(file1).use { SentryFileOutputStream(file2).write(it.readBytes()) }
69+
```
70+
71+
Similarly, `FileReader`/`FileWriter` can be instrumented through `SentryFileReader`/`SentryFileWriter`:
72+
73+
_Old_:
74+
```java
75+
import java.io.File;
76+
import java.io.FileReader;
77+
import java.io.FileWriter;
78+
79+
File file1 = new File("file1.txt");
80+
File file2 = new File("file2.txt");
81+
try (FileReader reader = new FileReader(file1)) {
82+
char[] buffer = new char[1024];
83+
try (FileWriter writer = FileWriter(file2, true)) {
84+
int read;
85+
while (true) {
86+
read = reader.read(buffer, 0, buffer.length);
87+
if (read == -1) {
88+
break;
89+
}
90+
writer.write(buffer, 0, buffer.length);
91+
}
92+
writer.flush();
93+
}
94+
}
95+
```
96+
97+
```kotlin
98+
import java.io.File
99+
import java.io.FileReader
100+
import java.io.FileWriter
101+
102+
val file1 = File("file1.txt")
103+
val file2 = File("file2.txt")
104+
FileReader(file1).use { FileWriter(file2).write(it.readText()) }
105+
```
106+
107+
_New_:
108+
```java
109+
import io.sentry.instrumentation.file.SentryFileReader;
110+
import io.sentry.instrumentation.file.SentryFileWriter;
111+
import java.io.File;
112+
import java.io.FileReader;
113+
import java.io.FileWriter;
114+
115+
File file1 = new File("file1.txt");
116+
File file2 = new File("file2.txt");
117+
try (FileReader reader = new SentryFileReader(file1)) {
118+
char[] buffer = new char[1024];
119+
try (FileWriter writer = SentryFileWriter(file2, true)) {
120+
int read;
121+
while (true) {
122+
read = reader.read(buffer, 0, buffer.length);
123+
if (read == -1) {
124+
break;
125+
}
126+
writer.write(buffer, 0, buffer.length);
127+
}
128+
writer.flush();
129+
}
130+
}
131+
```
132+
133+
```kotlin
134+
import io.sentry.instrumentation.file.SentryFileReader
135+
import io.sentry.instrumentation.file.SentryFileWriter
136+
import java.io.File
137+
138+
val file1 = File("file1.txt")
139+
val file2 = File("file2.txt")
140+
SentryFileReader(file1).use { SentryFileWriter(file2).write(it.readText()) }
141+
```

src/platforms/android/common/gradle.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ enum class InstrumentationFeature {
232232
* [java.io.FileOutputStream], [java.io.FileReader], [java.io.FileWriter].
233233
* This feature uses bytecode manipulation and replaces the above
234234
* mentioned classes with Sentry-specific implementations.
235+
*
236+
* Requires sentry-android SDK version 5.5.0 and above
235237
*/
236238
FILE_IO
237239
}

src/platforms/android/common/performance/instrumentation/automatic-instrumentation.mdx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ For more information see our [Apollo integration](/platforms/android/configurati
201201

202202
### SQLite and Room Instrumentation
203203

204-
The [Sentry Android Gradle Plugin](/platforms/android/gradle/) does the tracing auto instrumentation using bytecode manipulation for `androidx.sqlite` and `androidx.room` libraries.
204+
The [Sentry Android Gradle Plugin](/platforms/android/gradle/) does tracing auto instrumentation using bytecode manipulation for `androidx.sqlite` and `androidx.room` libraries.
205205

206206
The Plugin injects a code snippet that starts a span out of the active span bound to the scope for each `CRUD` operation. The SDK sets the span `operation` to `db` and `description` to the SQL Query if available.
207207

@@ -210,3 +210,19 @@ The span finishes once the operation has been executed. The span `status` is set
210210
When the operation throws an `Exception`, Sentry's SDK associates this exception to the running span. If you haven't set the SDK to swallow the exception and capture it, the span and SentryEvent will be linked when viewing it on the **Issue Details** page in sentry.io.
211211

212212
For more information see our [Room and SQLite integration](/platforms/android/configuration/integrations/room-and-sqlite/).
213+
214+
### File I/O Instrumentation
215+
216+
The [Sentry Android Gradle Plugin](/platforms/android/gradle/) does tracing auto instrumentation using bytecode manipulation for `java.io.FileInputStream`, `java.io.FileOutputStream`, `java.io.FileReader`, and `java.io.FileWriter`.
217+
218+
The plugin replaces the aforementioned classes with custom Sentry-specific implementations.
219+
220+
The Sentry-specific File I/O implementation starts a span out of the active span, bound to the scope for each File I/O operation. The SDK sets the span `operation` to `file.write`/`file.read` and `description` to `filename (pretty-printed file size)`, e.g. `file.txt (123 kB)`
221+
222+
In addition, the span contains other useful information such as `file.size` (raw number of bytes) and `file.path` (an absolute path to the file) as part of the `data` payload.
223+
224+
The span finishes once the operation has been executed. The span `status` is set to `SpanStatus.OK` if successful or `SpanStatus.INTERNAL_ERROR` if there was any error.
225+
226+
When the operation throws an `Exception`, Sentry's SDK associates this exception to the running span. If you haven't set the SDK to swallow the exception and capture it, the span and SentryEvent will be linked when viewing it on the **Issue Details** page in sentry.io.
227+
228+
For more information see our [File I/O integration](/platforms/android/configuration/integrations/file-io/).
Loading
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
---
2+
title: File I/O
3+
caseStyle: camelCase
4+
supportLevel: production
5+
categories:
6+
- mobile
7+
---
8+
9+
<Note>
10+
11+
Supported in Sentry's Android SDK version `5.5.0` and above.
12+
13+
Supported in Sentry Android Gradle Plugin version `3.0.0` and above.
14+
15+
</Note>
16+
17+
The [Sentry Android Gradle Plugin](/platforms/android/gradle/) provides File I/O support through bytecode manipulation. The source can be found [on GitHub](https://github.com/getsentry/sentry-android-gradle-plugin/tree/main/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation).
18+
19+
On this page, we get you up and running with Sentry's File I/O Integration, so that it will automatically start a span out of the active transaction, bound to the scope for each file input/output stream operation.
20+
21+
## Install
22+
23+
To use the File I/O integration, add the Sentry Android Gradle plugin and the Sentry Android SDK (version `5.5.0` or above) in `build.gradle`:
24+
25+
```groovy
26+
buildscript {
27+
repositories {
28+
mavenCentral()
29+
}
30+
}
31+
32+
plugins {
33+
id "io.sentry.android.gradle" version "3.0.0-beta.3"
34+
}
35+
36+
dependencies {
37+
implementation 'io.sentry:sentry-android:{{ packages.version('sentry.java.android', '5.0.0') }}'
38+
}
39+
```
40+
41+
```kotlin
42+
buildscript {
43+
repositories {
44+
mavenCentral()
45+
}
46+
}
47+
48+
plugins {
49+
id("io.sentry.android.gradle") version "3.0.0-beta.3"
50+
}
51+
52+
dependencies {
53+
implementation("io.sentry:sentry-android:{{ packages.version('sentry.java.android', '5.0.0') }}")
54+
}
55+
```
56+
57+
<Note>
58+
59+
Make sure, that [performance monitoring](/platforms/android/performance/#configure-the-sample-rate) is enabled.
60+
61+
</Note>
62+
63+
## Configure
64+
65+
In general, no further configuration is required as the auto-instrumentation is enabled by default. If you would like to disable the file I/O instrumentation feature, we expose a configuration option for that:
66+
67+
```groovy
68+
import io.sentry.android.gradle.InstrumentationFeature
69+
70+
sentry {
71+
tracingInstrumentation {
72+
enabled = true
73+
features = EnumSet.allOf(InstrumentationFeature) - InstrumentationFeature.FILE_IO
74+
}
75+
}
76+
```
77+
78+
```kotlin
79+
import java.util.EnumSet
80+
import io.sentry.android.gradle.InstrumentationFeature
81+
82+
sentry {
83+
tracingInstrumentation {
84+
enabled.set(true)
85+
features.set(EnumSet.allOf(InstrumentationFeature::class.java) - InstrumentationFeature.FILE_IO)
86+
}
87+
}
88+
```
89+
90+
## Verify
91+
92+
Assuming you have the following (reduced) code snippet performing a File I/O operation:
93+
94+
```kotlin
95+
import android.os.Bundle
96+
import android.widget.Button
97+
import android.widget.TextView
98+
import androidx.activity.ComponentActivity
99+
import io.sentry.Sentry
100+
import io.sentry.SpanStatus
101+
import java.io.File
102+
103+
class LyricsActivity : ComponentActivity() {
104+
105+
override fun onCreate(savedInstanceState: Bundle?) {
106+
super.onCreate(savedInstanceState)
107+
findViewById<Button>(R.id.load_lyrics).setOnClickListener {
108+
val transaction = Sentry.startTransaction(
109+
name = "Track Interaction",
110+
operation = "ui.action.lyrics",
111+
bindToScope = true
112+
)
113+
114+
val file = File(context.filesDir, "lyrics.txt")
115+
116+
val lyricsTextView = findViewById<TextView>(R.id.lyrics)
117+
lyricsTextView.setText(file.readText())
118+
119+
transaction.finish(SpanStatus.OK)
120+
}
121+
}
122+
}
123+
```
124+
125+
To view the recorded transaction, log into [sentry.io](https://sentry.io) and open your project. Clicking **Performance** will open a page with transactions, where you can select the just recorded transaction with the name `Track Interaction`. The event will look similar to this:
126+
127+
![File I/O performance instrumentation](file-io-instrumentation.png)
128+
129+
<Note>
130+
131+
At the moment, we only support `java.io.FileInputStream`, `java.io.FileOutputStream`, `java.io.FileReader` and `java.io.FileWriter` classes for auto-instrumentation.
132+
133+
</Note>
134+
135+
## (Optional) Manual Instrumentation
136+
137+
Alternatively, if you are not using our Gradle Plugin, the Android SDK provides the capability to manually instrument File I/O operations through the custom Sentry-specific implementations.
138+
139+
<PlatformContent includePath="performance/file-io-instrumentation" />
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
title: File I/O Integration
3+
sidebar_order: 60
4+
description: "Learn how to capture the performance of File I/O operations."
5+
notSupported:
6+
- java.logback
7+
- java.log4j2
8+
- java.jul
9+
---
10+
11+
<Note>
12+
13+
Capturing transactions requires that you first <PlatformLink to="/performance/">set up performance monitoring</PlatformLink> if you haven't already.
14+
15+
</Note>
16+
17+
Sentry File I/O integration provides the `SentryFileInputStream`/`SentryFileOutputStream` and `SentryFileReader`/`SentryFileWriter`, which create a span for each File read/write operation.
18+
19+
### Install
20+
21+
The File I/O Integration is available under the core Java SDK package.
22+
23+
```xml {tabTitle:Maven}
24+
<dependency>
25+
<groupId>io.sentry</groupId>
26+
<artifactId>sentry</artifactId>
27+
<version>{{ packages.version('sentry.java', '4.2.0') }}</version>
28+
</dependency>
29+
```
30+
31+
```groovy {tabTitle:Gradle}
32+
implementation 'io.sentry:sentry:{{ packages.version('sentry.java', '4.2.0') }}'
33+
```
34+
35+
```scala {tabTitle:SBT}
36+
libraryDependencies += "io.sentry" % "sentry" % "{{ packages.version('sentry.java', '4.2.0') }}"
37+
```
38+
39+
For other dependency managers, see the [central Maven repository](https://search.maven.org/artifact/io.sentry/sentry).
40+
41+
### Configure
42+
43+
<PlatformContent includePath="performance/file-io-instrumentation" />

0 commit comments

Comments
 (0)