or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdconcurrency.mdcore-effects.mddependency-injection.mderror-handling.mdindex.mdmetrics.mdresource-management.mdservices.mdstm.mdstreams.mdtesting.md

metrics.mddocs/

0

# Metrics and Observability

1

2

ZIO provides comprehensive metrics and observability capabilities for monitoring application performance, collecting telemetry data, and gaining insights into system behavior.

3

4

## Capabilities

5

6

### Metric System

7

8

ZIO's metric system allows you to collect, aggregate, and export various types of metrics with composable metric definitions.

9

10

```scala { .api }

11

/**

12

* A Metric represents a composable way to collect measurements

13

*/

14

sealed trait Metric[In, Out] {

15

/** Contramap the input type */

16

def contramap[In2](f: In2 => In): Metric[In2, Out]

17

18

/** Map the output type */

19

def map[Out2](f: Out => Out2): Metric[In, Out2]

20

21

/** Combine with another metric */

22

def zip[In2, Out2](that: Metric[In2, Out2]): Metric[(In, In2), (Out, Out2)]

23

24

/** Add tags to the metric */

25

def tagged(tag: MetricLabel, tags: MetricLabel*): Metric[In, Out]

26

27

/** Add tags conditionally */

28

def taggedWith[A](f: A => Set[MetricLabel]): Metric[(In, A), Out]

29

}

30

31

/**

32

* Common metric types

33

*/

34

object Metric {

35

/** Counter that only increases */

36

def counter(name: String): Metric[Double, MetricState.Counter]

37

38

/** Gauge that can increase or decrease */

39

def gauge(name: String): Metric[Double, MetricState.Gauge]

40

41

/** Histogram for distribution measurements */

42

def histogram(name: String, boundaries: MetricKeyType.Histogram.Boundaries): Metric[Double, MetricState.Histogram]

43

44

/** Summary for tracking count, sum, min, max */

45

def summary(name: String): Metric[Double, MetricState.Summary]

46

47

/** Set gauge for tracking distinct values */

48

def setGauge(name: String): Metric[Set[String], MetricState.Gauge]

49

50

/** Frequency metric for counting occurrences */

51

def frequency(name: String): Metric[String, MetricState.Frequency]

52

}

53

54

/**

55

* Metric labels for categorization

56

*/

57

case class MetricLabel(key: String, value: String)

58

59

object MetricLabel {

60

def apply(key: String, value: String): MetricLabel = new MetricLabel(key, value)

61

}

62

63

/**

64

* Metric key for identification

65

*/

66

case class MetricKey[Type <: MetricKeyType](

67

name: String,

68

keyType: Type,

69

description: Option[String] = None,

70

tags: Set[MetricLabel] = Set.empty

71

)

72

```

73

74

**Usage Examples:**

75

76

```scala

77

import zio._

78

import zio.metrics._

79

80

// Define metrics

81

val requestCounter = Metric.counter("http_requests_total")

82

.tagged(MetricLabel("service", "api"))

83

84

val responseTimeHistogram = Metric.histogram(

85

"http_request_duration_seconds",

86

MetricKeyType.Histogram.Boundaries.exponential(0.001, 2.0, 10)

87

).tagged(MetricLabel("endpoint", "/users"))

88

89

val activeConnectionsGauge = Metric.gauge("active_connections")

90

91

// Use metrics in application code

92

val httpHandler = for {

93

startTime <- Clock.nanoTime

94

95

// Increment request counter

96

_ <- requestCounter.update(1.0)

97

98

// Increment active connections

99

_ <- activeConnectionsGauge.update(1.0)

100

101

// Process request

102

response <- processRequest()

103

104

// Record response time

105

endTime <- Clock.nanoTime

106

duration = (endTime - startTime) / 1e9

107

_ <- responseTimeHistogram.update(duration)

108

109

// Decrement active connections

110

_ <- activeConnectionsGauge.update(-1.0)

111

112

} yield response

113

```

114

115

### Metric Client

116

117

The metric client provides centralized metric collection and export capabilities.

118

119

```scala { .api }

120

/**

121

* Client for collecting and exporting metrics

122

*/

123

trait MetricClient {

124

/** Get current snapshot of all metrics */

125

def snapshot: UIO[Set[MetricPair.Untyped]]

126

127

/** Track a metric value */

128

def track[In, Out](metric: Metric[In, Out], value: In): UIO[Unit]

129

130

/** Get specific metric state */

131

def get[Out](key: MetricKey[_]): UIO[Option[Out]]

132

}

133

134

/**

135

* Metric pair containing key and state

136

*/

137

sealed trait MetricPair[+Type <: MetricKeyType] {

138

def metricKey: MetricKey[Type]

139

def metricState: MetricState

140

}

141

142

object MetricPair {

143

type Untyped = MetricPair[MetricKeyType]

144

}

145

146

/**

147

* Different types of metric states

148

*/

149

sealed trait MetricState

150

151

object MetricState {

152

/** Counter state */

153

final case class Counter(count: Double, startTime: java.time.Instant) extends MetricState

154

155

/** Gauge state */

156

final case class Gauge(value: Double, startTime: java.time.Instant) extends MetricState

157

158

/** Histogram state */

159

final case class Histogram(

160

buckets: Chunk[(Double, Long)],

161

count: Long,

162

min: Double,

163

max: Double,

164

sum: Double,

165

startTime: java.time.Instant

166

) extends MetricState

167

168

/** Summary state */

169

final case class Summary(

170

error: Double,

171

quantiles: Chunk[(Double, Option[Double])],

172

count: Long,

173

min: Double,

174

max: Double,

175

sum: Double,

176

startTime: java.time.Instant

177

) extends MetricState

178

179

/** Frequency state */

180

final case class Frequency(occurrences: Map[String, Long]) extends MetricState

181

}

182

```

183

184

**Usage Examples:**

185

186

```scala

187

// Create and configure metric client

188

val metricClientLayer = ZLayer.succeed(MetricClient.default)

189

190

// Collect metrics snapshot

191

val metricsReport = for {

192

client <- ZIO.service[MetricClient]

193

snapshot <- client.snapshot

194

_ <- ZIO.foreach(snapshot) { pair =>

195

Console.printLine(s"${pair.metricKey.name}: ${pair.metricState}")

196

}

197

} yield ()

198

199

// Custom metric tracking

200

val customTracking = for {

201

client <- ZIO.service[MetricClient]

202

metric = Metric.counter("custom_events")

203

_ <- client.track(metric, 1.0)

204

state <- client.get(metric.key)

205

} yield state

206

```

207

208

### Built-in Metrics

209

210

ZIO automatically collects various system and runtime metrics when enabled.

211

212

```scala { .api }

213

/**

214

* JVM and system metrics automatically collected

215

*/

216

object BuiltInMetrics {

217

/** JVM memory usage metrics */

218

val jvmMemoryUsed: Metric[Any, MetricState.Gauge]

219

val jvmMemoryCommitted: Metric[Any, MetricState.Gauge]

220

val jvmMemoryMax: Metric[Any, MetricState.Gauge]

221

222

/** JVM garbage collection metrics */

223

val jvmGcTime: Metric[Any, MetricState.Counter]

224

val jvmGcCollections: Metric[Any, MetricState.Counter]

225

226

/** Thread pool metrics */

227

val jvmThreadsActive: Metric[Any, MetricState.Gauge]

228

val jvmThreadsDaemon: Metric[Any, MetricState.Gauge]

229

val jvmThreadsPeak: Metric[Any, MetricState.Gauge]

230

231

/** ZIO fiber metrics */

232

val fiberCount: Metric[Any, MetricState.Gauge]

233

val fiberStarted: Metric[Any, MetricState.Counter]

234

val fiberCompleted: Metric[Any, MetricState.Counter]

235

236

/** System CPU and load metrics */

237

val systemCpuUsage: Metric[Any, MetricState.Gauge]

238

val systemLoadAverage: Metric[Any, MetricState.Gauge]

239

240

/** Enable built-in metrics collection */

241

def enable: ZLayer[Any, Nothing, Unit]

242

}

243

```

244

245

**Usage Examples:**

246

247

```scala

248

// Enable built-in metrics

249

val app = myApplication.provide(

250

// Other layers

251

MetricClient.default,

252

BuiltInMetrics.enable

253

)

254

255

// Monitor fiber lifecycle

256

val fiberMonitoring = for {

257

_ <- Console.printLine("Starting intensive computation")

258

259

// This will be tracked by fiber metrics

260

fibers <- ZIO.foreach(1 to 100) { i =>

261

intensiveComputation(i).fork

262

}

263

264

results <- ZIO.foreach(fibers)(_.join)

265

266

// Check current fiber count

267

client <- ZIO.service[MetricClient]

268

fiberCount <- client.get(BuiltInMetrics.fiberCount.key)

269

_ <- Console.printLine(s"Current fiber count: $fiberCount")

270

271

} yield results

272

```

273

274

### Metric Aspects

275

276

Metric aspects provide declarative ways to add metrics to ZIO effects and layers.

277

278

```scala { .api }

279

/**

280

* Aspects for adding metrics to effects

281

*/

282

object MetricAspect {

283

/** Count executions of an effect */

284

def count(metric: Metric[Long, MetricState.Counter]): ZIOAspect[Nothing, Any, Nothing, Any, Nothing, Any]

285

286

/** Time duration of effect execution */

287

def timed(metric: Metric[Duration, MetricState.Histogram]): ZIOAspect[Nothing, Any, Nothing, Any, Nothing, Any]

288

289

/** Track gauge value during effect */

290

def trackGauge(metric: Metric[Double, MetricState.Gauge], value: => Double): ZIOAspect[Nothing, Any, Nothing, Any, Nothing, Any]

291

292

/** Count successes and failures separately */

293

def countErrors(

294

successMetric: Metric[Long, MetricState.Counter],

295

errorMetric: Metric[Long, MetricState.Counter]

296

): ZIOAspect[Nothing, Any, Nothing, Any, Nothing, Any]

297

298

/** Track different metrics based on result */

299

def trackResult[E, A](

300

f: Either[E, A] => List[(Metric[Double, _], Double)]

301

): ZIOAspect[Nothing, Any, E, E, A, A]

302

}

303

```

304

305

**Usage Examples:**

306

307

```scala

308

// Add metrics to effects using aspects

309

val databaseQuery = queryDatabase(userId)

310

@@ MetricAspect.count(Metric.counter("db_queries"))

311

@@ MetricAspect.timed(Metric.histogram("db_query_duration", boundaries))

312

@@ MetricAspect.countErrors(

313

Metric.counter("db_queries_success"),

314

Metric.counter("db_queries_error")

315

)

316

317

// Track business metrics

318

val orderProcessing = processOrder(order)

319

@@ MetricAspect.trackResult {

320

case Right(order) => List(

321

(Metric.counter("orders_completed"), 1.0),

322

(Metric.gauge("order_value"), order.totalAmount)

323

)

324

case Left(error) => List(

325

(Metric.counter("orders_failed"), 1.0)

326

)

327

}

328

329

// Track resource usage

330

val resourceIntensiveTask = computeResults()

331

@@ MetricAspect.trackGauge(Metric.gauge("cpu_intensive_tasks"), 1.0)

332

```

333

334

### Metric Export and Integration

335

336

Export metrics to external monitoring systems and integrate with observability platforms.

337

338

```scala { .api }

339

/**

340

* Metric exporters for external systems

341

*/

342

trait MetricExporter {

343

/** Export metrics snapshot */

344

def export(snapshot: Set[MetricPair.Untyped]): Task[Unit]

345

}

346

347

/**

348

* Common metric export formats

349

*/

350

object MetricExporter {

351

/** Export to Prometheus format */

352

def prometheus(registry: Registry): MetricExporter

353

354

/** Export to StatsD */

355

def statsD(client: StatsDClient): MetricExporter

356

357

/** Export to console for debugging */

358

val console: MetricExporter

359

360

/** Export to JSON format */

361

def json(writer: JsonWriter): MetricExporter

362

363

/** Composite exporter for multiple destinations */

364

def composite(exporters: MetricExporter*): MetricExporter

365

}

366

367

/**

368

* Periodic metric export scheduler

369

*/

370

object MetricScheduler {

371

/** Schedule periodic metric exports */

372

def schedule(

373

client: MetricClient,

374

exporter: MetricExporter,

375

interval: Duration

376

): ZIO[Any, Nothing, Fiber.Runtime[Throwable, Nothing]]

377

}

378

```

379

380

**Usage Examples:**

381

382

```scala

383

// Set up metric export to multiple systems

384

val metricExportLayer = ZLayer.scoped {

385

for {

386

client <- ZIO.service[MetricClient]

387

388

// Create composite exporter

389

exporter = MetricExporter.composite(

390

MetricExporter.prometheus(prometheusRegistry),

391

MetricExporter.statsD(statsDClient),

392

MetricExporter.console // For debugging

393

)

394

395

// Schedule periodic export

396

scheduler <- MetricScheduler.schedule(client, exporter, 30.seconds)

397

398

// Ensure cleanup

399

_ <- ZIO.addFinalizer(scheduler.interrupt.ignore)

400

401

} yield ()

402

}

403

404

// Full application with metrics

405

val monitoredApp = myApplication.provide(

406

MetricClient.default,

407

BuiltInMetrics.enable,

408

metricExportLayer,

409

// Other application layers

410

)

411

412

// Manual metric export

413

val exportMetrics = for {

414

client <- ZIO.service[MetricClient]

415

snapshot <- client.snapshot

416

_ <- MetricExporter.console.export(snapshot)

417

} yield ()

418

```

419

420

### Performance Monitoring

421

422

Advanced performance monitoring and profiling capabilities for production applications.

423

424

```scala { .api }

425

/**

426

* Performance monitoring utilities

427

*/

428

object PerformanceMonitoring {

429

/** Monitor method execution with detailed timing */

430

def profileMethod[R, E, A](

431

methodName: String,

432

thresholds: Map[String, Duration] = Map.empty

433

)(effect: ZIO[R, E, A]): ZIO[R, E, A]

434

435

/** Monitor memory allocation during effect */

436

def trackMemory[R, E, A](effect: ZIO[R, E, A]): ZIO[R, E, (A, MemoryUsage)]

437

438

/** Monitor fiber scheduling and execution */

439

def trackFiberMetrics[R, E, A](effect: ZIO[R, E, A]): ZIO[R, E, A]

440

441

/** Create performance dashboard data */

442

def dashboardSnapshot: UIO[PerformanceDashboard]

443

}

444

445

/**

446

* Memory usage information

447

*/

448

case class MemoryUsage(

449

heapUsed: Long,

450

heapCommitted: Long,

451

heapMax: Long,

452

nonHeapUsed: Long,

453

nonHeapCommitted: Long

454

)

455

456

/**

457

* Performance dashboard data

458

*/

459

case class PerformanceDashboard(

460

uptime: Duration,

461

fiberStats: FiberStats,

462

memoryStats: MemoryUsage,

463

gcStats: GCStats,

464

threadStats: ThreadStats

465

)

466

```

467

468

**Usage Examples:**

469

470

```scala

471

// Profile critical methods

472

val criticalOperation = performCriticalTask()

473

@@ PerformanceMonitoring.profileMethod(

474

"critical_task",

475

Map(

476

"warning" -> 100.millis,

477

"critical" -> 500.millis

478

)

479

)

480

481

// Monitor memory-intensive operations

482

val memoryIntensiveTask = for {

483

(result, memUsage) <- PerformanceMonitoring.trackMemory {

484

processLargeDataset(dataset)

485

}

486

_ <- Console.printLine(s"Memory used: ${memUsage.heapUsed / 1024 / 1024} MB")

487

} yield result

488

489

// Create performance monitoring dashboard

490

val performanceDashboard = for {

491

dashboard <- PerformanceMonitoring.dashboardSnapshot

492

_ <- Console.printLine(s"Uptime: ${dashboard.uptime}")

493

_ <- Console.printLine(s"Active fibers: ${dashboard.fiberStats.active}")

494

_ <- Console.printLine(s"Heap usage: ${dashboard.memoryStats.heapUsed}")

495

} yield dashboard

496

```