Network (HTTP)

Specto supports opt-in instrumentation for HTTP requests. While tracing is active, Specto monitors the network activity of your application, groups requests based on URLs, and provides information about their durations, errors that may occur, and more.

Unlike other metrics, which are collected automatically, network instrumentation may require some additional setup.


Setup (iOS)

HTTP instrumentation will be enabled automatically when using the shared URL session (URLSession.sharedSession). For URLSession instances that you create on your own, or for sessions managed by a 3rd party HTTP framework, you have to call Specto. enableNetworkRequestTracing(in:) on the URLSessionConfiguration:

let configuration: URLSessionConfiguration = ...
Specto.enableNetworkRequestTracing(in: configuration)
let session = URLSession(configuration: configuration)
Specto.startTrace(interactionName: "test-network-requests")
// Use session to make HTTP requests
let configuration: URLSessionConfiguration = ...
Specto.enableNetworkRequestTracing(in: configuration)
let manager = Alamofire.Manager(configuration: configuration)
Specto.startTrace(interactionName: "test-network-requests")
// Use manager to make HTTP requests
NSURLSessionConfiguration *configuration = ...
[Specto enableNetworkRequestTracingInSessionConfiguration:configuration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
[Specto startTrace:@"test-network-requests"];
// Use session to make HTTP requests

πŸ“˜

On iOS, Specto currently does not support HTTP libraries that are not built on top of URLSession.

Setup (Android)

To enable HTTP instrumentation, add the SpectoInterceptor to your OkHttpClient:

val client = OkHttpClient.Builder()
    .addInterceptor(SpectoInterceptor())
    .build()
OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new SpectoInterceptor())
    .build();

πŸ“˜

On Android, Specto currently does not support HTTP libraries other than OkHttp.

URL Patterns

Specto only logs information about HTTP requests that match a URL group, which is defined using a pattern. These URL groups are defined during initialization of the SDK:

Specto.setUp(APIKey: "<api-key>", configuration: SpectoClientConfiguration(urlGroups: [
    SpectoURLGroup("main", pattern: "example.com/main"),
    SpectoURLGroup("best-ofs", pattern: "example.com/*/best"),
    SpectoURLGroup("books", pattern: "example.com/books/**"),
    SpectoURLGroup("movies", pattern: "example.com/movies/**"),
    SpectoURLGroup("static", pattern: "static.example.com/**"),
]))
SpectoInterceptor {
    "example.com/main" to "main"
    "example.com/*/best" to "best-ofs"
    "example.com/books/**" to "books"
    "example.com/movies/**" to "movies"
    "static.example.com/**" to "static"
}
[Specto setUpWithAPIKey:@"<api-key>" clientConfiguration:
    [[SpectoClientConfiguration alloc] initWithURLGroups:@[
          [SpectoURLGroup groupName:@"main" pattern:@"example.com/*/best"],
          [SpectoURLGroup groupName:@"best-ofs" pattern:@"google.com/b"],
          [SpectoURLGroup groupName:@"books" pattern:@"example.com/books/**"],
          [SpectoURLGroup groupName:@"movies" pattern:@"example.com/movies/**"],
          [SpectoURLGroup groupName:@"static" pattern:@"static.example.com/**"],
      ]]];
new SpectoInterceptor(
    new SpectoUrlGroups.Builder()
        .add("example.com/main", "main")
        .add("example.com/*/best", "best-ofs")
        .add("example.com/books/**", "books")
        .add("example.com/movies/**", "movies")
        .add("static.example.com/**", "static")
        .build()
);

The statistics of requests belonging to the same group will be aggregated in the Specto dashboard, and the URL patterns follow these rules:

  • Contains only the host and the path (and optionally the port).
  • * matches an entire, arbitrary path segment.
  • ** matches an arbitrary path suffix, including no suffix.
  • The first match decides the group.

πŸ“˜

Note: when specifying your patterns, omit any protocols, such as https://.

Examples

Pattern

URL

example.com/foo/bar

example.com/foo/bar βœ…

example.com/*/bar

example.com/foo/bar βœ…
example.com/bah/bar βœ…
example.com/bar ❌
example.com/foo/bah/bar ❌

example.com///bar

example.com/foo/seg/bar βœ…
example.com/net/qui/bar βœ…

example.com/foo/*

example.com/foo/bar βœ…
example.com/foo/qui βœ…
example.com/foo ❌

example.com/foo/**

example.com/foo βœ…
example.com/foo/bar βœ…
example.com/foo/bar/more/segments βœ…

Custom Mapper (Android)

If using URL patterns is not a good fit, you also have the option of providing your own mapper implementation which maps each request to a group name:

SpectoInterceptor(object : SpectoNetworkRequestMapper {
    override fun mapToGroup(request: Request): String? {
        return request.tag()?.toString()
    }
})
new SpectoInterceptor(new SpectoNetworkRequestMapper() {
    @Nullable
    @Override
    public String mapToGroup(@NotNull Request request) {
        Object tag = request.tag();
        if (tag != null) {
            return tag.toString();
        } else {
            return null;
        }
    }
});

Returning null prevents the request from being recorded by Specto altogether.

If you are using Retrofit, SpectoRetrofitNetworkRequestMapper, if used, will automatically map requests by Retrofit interface class and method:

val interceptor = SpectoInterceptor(SpectoRetrofitNetworkRequestMapper())
val retrofit = Retrofit.Builder()
    .baseUrl(…)
    .client(
        OkHttpClient.Builder()
            .addInterceptor(interceptor)
            .build()
        )
    )
    .build()

Privacy

Specto does not send raw URLs or request bodies to our backend. We log the group name, pattern, HTTP method (GET, POST, etc.), and request duration for each matching request. All pattern matching happens on the client and not on our backend.