• EnglishEspañol日本語한국어Português
  • Log inStart now

Scala ZIO instrumentation

ZIO is a Scala library used to run asynchronous operations. In order to fully leverage ZIO's lazy evaluated structure, we offer a ZIO API to create transactions and segments.

Install the ZIO API

To access the API class add the following information to your Scala configuration file depending on the version of ZIO you are using.

Supported Scala versions are 2.11, 2.12, and 2.13. Scala 3.0 users can use the 2.13 jar. The minimum Scala version for ZIO v2 is 2.12.

Important

For best results when using the API, ensure that you have the latest Java agent release.

  • The New Relic ZIO v1 API requires Java agent 7.2.0 or higher.
  • The New Relic ZIO v2 API requires Java agent 8.10.0 or higher.

Use the ZIO API

You first need to make your import statement, and then you can create transactions and segments.

Make import statement

To leverage the ZIO API, make the following import statement for your version:

ZIO v1 API

import com.newrelic.zio.api.TraceOps

ZIO v2 API

import com.newrelic.zio2.api.TraceOps

The APIs for both are the same except for the package names.

Create transactions

You can lazily create transactions using the TraceOps.txn method. If a transaction already exists before the method is called, this method will be part of the existing transaction.

Important

Unlike the Scala API's transaction method, this method does not eagerly create a transaction. Instead you pass in a ZIO block in which an effect is created in a returned instance that lazily creates a transaction tracer. It ends when all ZIO operations end. As a result any code run outside any ZIO instance or operations will not be captured in the new transaction.

For example:

import com.newrelic.zio.api.TraceOps.{txn, traceFun, trace}
// or if using ZIO 2, comment out the line above and uncomment the line below
// import com.newrelic.zio2.api.TraceOps.{txn, traceFun, trace}
val x = txn {
// The segment named "not-captured" will not be
// captured in the transaction because it is not ran within Zio.
trace("not-captured") {
println("hello")
}
// The segment named "trace map UIO" will be
// captured as part of the transaction because it is ran within Zio.
ZIO.succeed(1).map(traceFun("trace map UIO")(i => i + 1))
}

Create segments

To create a segment for a synchronous code block use TraceOps.trace. For example:

import com.newrelic.zio.api.TraceOps.trace
// or if using ZIO 2, comment out the line above and uncomment the line below
// import com.newrelic.zio2.api.TraceOps.trace
trace("statement segment") {
val i = 1
val j = 2
println(i + j)
}
// trace can also be used as an expression
val x: Int = trace("expression segment") {
val i = 1
val j = 2
i + j
}
println(x) // 2

Important

TraceOps.trace only works with synchronous code. Any operations done through a ZIO effect, operation, or both should instead use TraceOps.asyncTrace (see below).

If you want to create a segment for an asynchronous code block using ZIO, use TraceOps.asyncTrace. This will ensure the timing for the segment includes the time taken for the ZIO effect or operation to complete.

import zio.ZIO
import com.newrelic.zio.api.TraceOps.asyncTrace
// or if using ZIO 2, comment out the line above and uncomment the line below
// import com.newrelic.zio2.api.TraceOps.asyncTrace
val x: ZIO[_, _, Int] = asyncTrace("segment name") {
ZIO.succeed(1) <*
ZIO.sleep(zio.duration.Duration.fromMillis(1.second.toMillis))
}.debug // prints 1 after the completion of the segment.

You can also use asyncTrace in Scala for comprehensions:

import zio.ZIO
import com.newrelic.zio.api.TraceOps.asyncTrace
// or if using ZIO 2, comment out the line above and uncomment the line below
// import com.newrelic.zio2.api.TraceOps.asyncTrace
val x: ZIO[_, _, Int] = for {
one <- asyncTrace("segment one")(ZIO.succeed(1))
two <- asyncTrace("segment two")(ZIO.succeed(one + 1))
three <- asyncTrace("segment three")(ZIO.succeed(two + 1))
} yield three
val x2 = x.debug // prints 3 on completion of the segments in x

If you want to create a segment for a synchronous anonymous function, use TraceOps.traceFun. For example:

import zio.ZIO
import com.newrelic.zio.api.TraceOps.asyncTraceFun
// or if using ZIO 2, comment out the line above and uncomment the line below
// import com.newrelic.zio2.api.TraceOps.asyncTraceFun
val x: ZIO[_, _, Int] = ZIO.succeed(1)
.map(traceFun("statement segment")(i => i + 1))
.debug // prints 2

If you want to create segment for an asynchronous function that returns a ZIO instance,
use TraceOps.asyncTraceFun. This will ensure the timing for the segment includes the time taken for the ZIO operations to complete. For example:

import zio.ZIO
import com.newrelic.zio.api.TraceOps.asyncTraceFun
// or if using ZIO 2, comment out the line above and uncomment the line below
// import com.newrelic.zio2.api.TraceOps.asyncTraceFun
val x: ZIO[_, _, Int] = ZIO.succeed(1)
.flatMap(asyncTraceFun("statement segment")(i => ZIO.succeed(i + 1)))
.debug // prints 2 on completion of the zio operations

More API functions

For more about the Java agent API and its functionality, see the Java agent API introduction.

Copyright © 2024 New Relic Inc.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.