or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context-management.mdindex.mdio-filesystem.mdlanguage-execution.mdmonitoring-management.mdproxy-system.mdsecurity-access.mdvalue-interop.md

monitoring-management.mddocs/

0

# Execution Monitoring and Resource Management

1

2

GraalVM Polyglot API provides comprehensive monitoring and resource management capabilities, including execution event tracking, resource consumption limits, exception handling, and performance profiling for polyglot applications.

3

4

## Management System

5

6

The Management class provides the foundation for monitoring polyglot execution through event listeners and profiling tools.

7

8

### Management Factory

9

10

```java { .api }

11

public final class Management {

12

/**

13

* Creates a new Management.Builder for configuration.

14

* @return new builder instance

15

*/

16

public static Management.Builder newBuilder();

17

18

/**

19

* Creates an execution listener for monitoring code execution.

20

* @return new ExecutionListener

21

*/

22

public ExecutionListener newExecutionListener();

23

}

24

```

25

26

### Management Configuration

27

28

```java { .api }

29

public static final class Management.Builder {

30

/**

31

* Builds the Management instance.

32

* @return configured Management

33

*/

34

public Management build();

35

}

36

```

37

38

**Management Setup Example:**

39

40

```java

41

import org.graalvm.polyglot.management.Management;

42

import org.graalvm.polyglot.management.ExecutionListener;

43

44

// Create management system

45

Management management = Management.newBuilder().build();

46

47

// Create execution listener

48

ExecutionListener listener = management.newExecutionListener();

49

50

// Configure monitoring...

51

```

52

53

## Execution Monitoring

54

55

ExecutionListener provides fine-grained monitoring of code execution, allowing you to track entry/exit events, performance metrics, and execution context.

56

57

### ExecutionListener Interface

58

59

```java { .api }

60

public final class ExecutionListener implements AutoCloseable {

61

/**

62

* Sets callback for execution entry events.

63

* @param listener callback to invoke on entry

64

*/

65

public void onEnter(Consumer<ExecutionEvent> listener);

66

67

/**

68

* Sets callback for execution return events.

69

* @param listener callback to invoke on return

70

*/

71

public void onReturn(Consumer<ExecutionEvent> listener);

72

73

/**

74

* Attaches listener to an engine for monitoring all contexts.

75

* @param engine the engine to monitor

76

*/

77

public void attach(Engine engine);

78

79

/**

80

* Attaches listener to a specific context.

81

* @param context the context to monitor

82

*/

83

public void attach(Context context);

84

85

/**

86

* Checks if the listener is attached to any engine or context.

87

* @return true if attached

88

*/

89

public boolean isAttached();

90

91

/**

92

* Checks if the listener has been closed.

93

* @return true if closed

94

*/

95

public boolean isClosed();

96

97

/**

98

* Closes the listener and detaches from all engines/contexts.

99

*/

100

@Override

101

public void close();

102

}

103

```

104

105

### ExecutionEvent Details

106

107

```java { .api }

108

public final class ExecutionEvent {

109

/**

110

* Gets the root function/method name being executed.

111

* @return root name or null if not available

112

*/

113

public String getRootName();

114

115

/**

116

* Gets the source location of the execution point.

117

* @return source location or null if not available

118

*/

119

public SourceSection getLocation();

120

121

/**

122

* Checks if this event represents a statement execution.

123

* @return true if statement

124

*/

125

public boolean isStatement();

126

127

/**

128

* Checks if this event represents an expression evaluation.

129

* @return true if expression

130

*/

131

public boolean isExpression();

132

133

/**

134

* Checks if this event represents root-level execution.

135

* @return true if root

136

*/

137

public boolean isRoot();

138

139

/**

140

* Gets input values for the execution (on entry).

141

* @return array of input values

142

*/

143

public Value[] getInputValues();

144

145

/**

146

* Gets the return value (on return events).

147

* @return return value or null

148

*/

149

public Value getReturnValue();

150

151

/**

152

* Gets exception if execution failed (on return events).

153

* @return exception or null if no exception

154

*/

155

public RuntimeException getException();

156

}

157

```

158

159

**Comprehensive Execution Monitoring Example:**

160

161

```java

162

import org.graalvm.polyglot.management.*;

163

import java.time.Instant;

164

import java.util.concurrent.ConcurrentHashMap;

165

import java.util.concurrent.atomic.AtomicLong;

166

167

public class DetailedExecutionMonitor {

168

private final Map<String, ExecutionStats> functionStats = new ConcurrentHashMap<>();

169

private final AtomicLong totalExecutions = new AtomicLong(0);

170

private final AtomicLong totalExecutionTime = new AtomicLong(0);

171

172

public void setupMonitoring(Context context) {

173

Management management = Management.newBuilder().build();

174

ExecutionListener listener = management.newExecutionListener();

175

176

// Track execution entry

177

listener.onEnter(this::onExecutionEnter);

178

179

// Track execution exit

180

listener.onReturn(this::onExecutionReturn);

181

182

// Attach to context

183

listener.attach(context);

184

185

// Setup automatic cleanup

186

Runtime.getRuntime().addShutdownHook(new Thread(() -> {

187

listener.close();

188

printStatistics();

189

}));

190

}

191

192

private void onExecutionEnter(ExecutionEvent event) {

193

String rootName = event.getRootName();

194

if (rootName != null) {

195

ExecutionStats stats = functionStats.computeIfAbsent(rootName,

196

k -> new ExecutionStats(k));

197

198

stats.enterExecution();

199

totalExecutions.incrementAndGet();

200

201

// Log entry with details

202

SourceSection location = event.getLocation();

203

if (location != null) {

204

System.out.printf("ENTER: %s at %s:%d%n",

205

rootName,

206

location.getSource().getName(),

207

location.getStartLine());

208

}

209

210

// Log input values

211

Value[] inputs = event.getInputValues();

212

if (inputs.length > 0) {

213

System.out.print(" Inputs: ");

214

for (int i = 0; i < inputs.length; i++) {

215

if (i > 0) System.out.print(", ");

216

System.out.print(inputs[i].toString());

217

}

218

System.out.println();

219

}

220

}

221

}

222

223

private void onExecutionReturn(ExecutionEvent event) {

224

String rootName = event.getRootName();

225

if (rootName != null) {

226

ExecutionStats stats = functionStats.get(rootName);

227

if (stats != null) {

228

long duration = stats.exitExecution();

229

totalExecutionTime.addAndGet(duration);

230

231

// Log return value or exception

232

RuntimeException exception = event.getException();

233

if (exception != null) {

234

System.out.printf("EXIT: %s (EXCEPTION: %s)%n",

235

rootName, exception.getMessage());

236

stats.recordException(exception);

237

} else {

238

Value returnValue = event.getReturnValue();

239

System.out.printf("EXIT: %s -> %s (took %d ns)%n",

240

rootName,

241

returnValue != null ? returnValue.toString() : "void",

242

duration);

243

}

244

}

245

}

246

}

247

248

public void printStatistics() {

249

System.out.println("\n=== Execution Statistics ===");

250

System.out.printf("Total executions: %d%n", totalExecutions.get());

251

System.out.printf("Total time: %.2f ms%n", totalExecutionTime.get() / 1_000_000.0);

252

253

functionStats.values().stream()

254

.sorted((a, b) -> Long.compare(b.getTotalTime(), a.getTotalTime()))

255

.forEach(stats -> {

256

System.out.printf("Function: %s%n", stats.getFunctionName());

257

System.out.printf(" Calls: %d%n", stats.getCallCount());

258

System.out.printf(" Total time: %.2f ms%n", stats.getTotalTime() / 1_000_000.0);

259

System.out.printf(" Average time: %.2f ms%n", stats.getAverageTime() / 1_000_000.0);

260

System.out.printf(" Exceptions: %d%n", stats.getExceptionCount());

261

});

262

}

263

264

private static class ExecutionStats {

265

private final String functionName;

266

private final AtomicLong callCount = new AtomicLong(0);

267

private final AtomicLong totalTime = new AtomicLong(0);

268

private final AtomicLong exceptionCount = new AtomicLong(0);

269

private volatile long enterTime;

270

271

public ExecutionStats(String functionName) {

272

this.functionName = functionName;

273

}

274

275

public void enterExecution() {

276

callCount.incrementAndGet();

277

enterTime = System.nanoTime();

278

}

279

280

public long exitExecution() {

281

long duration = System.nanoTime() - enterTime;

282

totalTime.addAndGet(duration);

283

return duration;

284

}

285

286

public void recordException(RuntimeException exception) {

287

exceptionCount.incrementAndGet();

288

}

289

290

// Getters...

291

public String getFunctionName() { return functionName; }

292

public long getCallCount() { return callCount.get(); }

293

public long getTotalTime() { return totalTime.get(); }

294

public long getAverageTime() {

295

long count = callCount.get();

296

return count > 0 ? totalTime.get() / count : 0;

297

}

298

public long getExceptionCount() { return exceptionCount.get(); }

299

}

300

}

301

302

// Usage

303

Context context = Context.create("js");

304

DetailedExecutionMonitor monitor = new DetailedExecutionMonitor();

305

monitor.setupMonitoring(context);

306

307

// Execute monitored code

308

context.eval("js", """

309

function fibonacci(n) {

310

if (n <= 1) return n;

311

return fibonacci(n - 1) + fibonacci(n - 2);

312

}

313

314

function calculate() {

315

let result = 0;

316

for (let i = 0; i < 10; i++) {

317

result += fibonacci(i);

318

}

319

return result;

320

}

321

322

calculate();

323

""");

324

```

325

326

## Resource Limits

327

328

ResourceLimits provides mechanisms to control and limit resource consumption during polyglot execution.

329

330

### ResourceLimits Configuration

331

332

```java { .api }

333

public final class ResourceLimits {

334

/**

335

* Creates a new ResourceLimits.Builder.

336

* @return new builder instance

337

*/

338

public static ResourceLimits.Builder newBuilder();

339

}

340

```

341

342

### ResourceLimits Builder

343

344

```java { .api }

345

public static final class ResourceLimits.Builder {

346

/**

347

* Sets statement execution limit.

348

* @param limit maximum number of statements to execute

349

* @param sourceFilter predicate to filter which sources are counted (null = all sources)

350

* @return this builder

351

*/

352

public ResourceLimits.Builder statementLimit(long limit, Predicate<Source> sourceFilter);

353

354

/**

355

* Sets callback for when resource limits are exceeded.

356

* @param onLimit callback to invoke on limit exceeded

357

* @return this builder

358

*/

359

public ResourceLimits.Builder onLimit(Consumer<ResourceLimitEvent> onLimit);

360

361

/**

362

* Builds the ResourceLimits.

363

* @return configured ResourceLimits

364

*/

365

public ResourceLimits build();

366

}

367

```

368

369

### ResourceLimitEvent

370

371

```java { .api }

372

public final class ResourceLimitEvent {

373

/**

374

* Gets the type of limit that was exceeded.

375

* @return limit type identifier

376

*/

377

public String getLimitType();

378

379

/**

380

* Gets the amount of resource consumed.

381

* @return consumed amount

382

*/

383

public long getConsumed();

384

385

/**

386

* Gets the configured limit value.

387

* @return limit value

388

*/

389

public long getLimit();

390

}

391

```

392

393

**Resource Limits Example:**

394

395

```java

396

import org.graalvm.polyglot.ResourceLimits;

397

import org.graalvm.polyglot.ResourceLimitEvent;

398

399

public class ResourceControlledExecution {

400

401

public static void executeWithLimits() {

402

// Configure resource limits

403

ResourceLimits limits = ResourceLimits.newBuilder()

404

.statementLimit(50000, source -> !source.isInternal()) // Only count user code

405

.onLimit(event -> {

406

System.err.printf("Resource limit exceeded: %s%n", event.getLimitType());

407

System.err.printf("Consumed: %d, Limit: %d%n",

408

event.getConsumed(), event.getLimit());

409

410

// Log for security audit

411

SecurityAuditLog.logResourceExhaustion(event);

412

413

// Could throw exception to terminate execution

414

throw new SecurityException("Statement limit exceeded: " + event.getConsumed());

415

})

416

.build();

417

418

// Create context with limits

419

Context context = Context.newBuilder("js")

420

.resourceLimits(limits)

421

.build();

422

423

try {

424

// This will trigger the limit

425

context.eval("js", """

426

let count = 0;

427

while (true) { // Infinite loop

428

count++;

429

if (count % 10000 === 0) {

430

console.log('Count:', count);

431

}

432

}

433

""");

434

} catch (PolyglotException e) {

435

if (e.isResourceExhausted()) {

436

System.err.println("Execution stopped due to resource exhaustion");

437

} else {

438

System.err.println("Other execution error: " + e.getMessage());

439

}

440

}

441

}

442

443

// Advanced resource management with custom limits

444

public static void advancedResourceControl() {

445

AtomicLong memoryUsage = new AtomicLong(0);

446

AtomicLong executionTime = new AtomicLong(System.nanoTime());

447

448

ResourceLimits limits = ResourceLimits.newBuilder()

449

.statementLimit(100000, null)

450

.onLimit(event -> {

451

// Check multiple resource types

452

long currentTime = System.nanoTime();

453

long elapsed = currentTime - executionTime.get();

454

455

if (elapsed > TimeUnit.SECONDS.toNanos(30)) { // 30 second timeout

456

throw new SecurityException("Execution timeout exceeded");

457

}

458

459

// Memory check (if available)

460

long currentMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

461

if (currentMemory > 100 * 1024 * 1024) { // 100MB limit

462

throw new SecurityException("Memory limit exceeded");

463

}

464

465

// Default action for statement limit

466

if ("StatementLimit".equals(event.getLimitType())) {

467

throw new SecurityException("Statement execution limit exceeded");

468

}

469

})

470

.build();

471

472

Context context = Context.newBuilder("js")

473

.resourceLimits(limits)

474

.build();

475

476

// Reset execution timer

477

executionTime.set(System.nanoTime());

478

479

try {

480

context.eval("js", userProvidedCode);

481

} catch (PolyglotException e) {

482

handleResourceExhaustion(e);

483

}

484

}

485

}

486

487

class SecurityAuditLog {

488

public static void logResourceExhaustion(ResourceLimitEvent event) {

489

System.err.printf("[SECURITY] Resource exhaustion - Type: %s, Consumed: %d, Limit: %d, Time: %s%n",

490

event.getLimitType(), event.getConsumed(), event.getLimit(), Instant.now());

491

}

492

}

493

```

494

495

## Exception Handling and Diagnostics

496

497

PolyglotException provides comprehensive error information for debugging and monitoring polyglot execution.

498

499

### PolyglotException Analysis

500

501

```java { .api }

502

public final class PolyglotException extends RuntimeException {

503

// Exception type classification

504

public boolean isHostException();

505

public boolean isGuestException();

506

public boolean isSyntaxError();

507

public boolean isIncompleteSource();

508

public boolean isCancelled();

509

public boolean isExit();

510

public boolean isInterrupted();

511

public boolean isInternalError();

512

public boolean isResourceExhausted();

513

514

// Exception details

515

public Value getGuestObject();

516

public SourceSection getSourceLocation();

517

public int getExitStatus();

518

public Throwable asHostException();

519

520

// Stack trace operations

521

public Iterable<StackFrame> getPolyglotStackTrace();

522

public void printStackTrace(PrintWriter s);

523

public void printStackTrace(PrintStream s);

524

}

525

```

526

527

### PolyglotException.StackFrame

528

529

```java { .api }

530

public static final class PolyglotException.StackFrame {

531

/**

532

* Gets the source location of this stack frame.

533

* @return source location or null

534

*/

535

public SourceSection getSourceLocation();

536

537

/**

538

* Gets the root name (function/method name).

539

* @return root name or null

540

*/

541

public String getRootName();

542

543

/**

544

* Checks if this is a host (Java) frame.

545

* @return true if host frame

546

*/

547

public boolean isHostFrame();

548

549

/**

550

* Checks if this is a guest language frame.

551

* @return true if guest frame

552

*/

553

public boolean isGuestFrame();

554

555

/**

556

* Gets the host method name (if host frame).

557

* @return method name or null

558

*/

559

public String toHostFrame();

560

}

561

```

562

563

**Comprehensive Exception Handling Example:**

564

565

```java

566

public class PolyglotExceptionAnalyzer {

567

568

public static void analyzeException(PolyglotException exception) {

569

System.out.println("=== Polyglot Exception Analysis ===");

570

571

// Classify exception type

572

if (exception.isHostException()) {

573

System.out.println("Type: Host Exception (Java)");

574

Throwable hostException = exception.asHostException();

575

System.out.println("Host Exception: " + hostException.getClass().getSimpleName());

576

System.out.println("Message: " + hostException.getMessage());

577

578

} else if (exception.isGuestException()) {

579

System.out.println("Type: Guest Exception");

580

Value guestObject = exception.getGuestObject();

581

if (guestObject != null) {

582

System.out.println("Guest Exception Object: " + guestObject.toString());

583

584

// Try to extract common exception properties

585

if (guestObject.hasMembers()) {

586

if (guestObject.hasMember("name")) {

587

System.out.println("Exception Name: " + guestObject.getMember("name").asString());

588

}

589

if (guestObject.hasMember("message")) {

590

System.out.println("Exception Message: " + guestObject.getMember("message").asString());

591

}

592

}

593

}

594

595

} else if (exception.isSyntaxError()) {

596

System.out.println("Type: Syntax Error");

597

598

} else if (exception.isResourceExhausted()) {

599

System.out.println("Type: Resource Exhausted");

600

601

} else if (exception.isInterrupted()) {

602

System.out.println("Type: Execution Interrupted");

603

604

} else if (exception.isCancelled()) {

605

System.out.println("Type: Execution Cancelled");

606

607

} else if (exception.isExit()) {

608

System.out.println("Type: Exit");

609

System.out.println("Exit Status: " + exception.getExitStatus());

610

}

611

612

// Source location information

613

SourceSection location = exception.getSourceLocation();

614

if (location != null) {

615

System.out.printf("Location: %s:%d:%d%n",

616

location.getSource().getName(),

617

location.getStartLine(),

618

location.getStartColumn());

619

620

if (location.isAvailable()) {

621

System.out.println("Source Code: " + location.getCharacters());

622

}

623

}

624

625

// Stack trace analysis

626

System.out.println("\n=== Stack Trace ===");

627

int frameIndex = 0;

628

for (PolyglotException.StackFrame frame : exception.getPolyglotStackTrace()) {

629

System.out.printf("#%d: ", frameIndex++);

630

631

if (frame.isHostFrame()) {

632

System.out.printf("[HOST] %s%n", frame.toHostFrame());

633

} else if (frame.isGuestFrame()) {

634

System.out.printf("[GUEST] %s", frame.getRootName() != null ? frame.getRootName() : "<anonymous>");

635

636

SourceSection frameLocation = frame.getSourceLocation();

637

if (frameLocation != null) {

638

System.out.printf(" at %s:%d%n",

639

frameLocation.getSource().getName(),

640

frameLocation.getStartLine());

641

} else {

642

System.out.println();

643

}

644

}

645

}

646

}

647

648

public static void executeWithDetailedErrorHandling(Context context, String code) {

649

try {

650

Value result = context.eval("js", code);

651

System.out.println("Execution successful: " + result);

652

653

} catch (PolyglotException e) {

654

analyzeException(e);

655

656

// Log for debugging

657

System.err.println("\n=== Full Stack Trace ===");

658

e.printStackTrace();

659

660

// Take appropriate action based on exception type

661

if (e.isResourceExhausted()) {

662

// Resource exhaustion - security concern

663

SecurityLogger.logResourceExhaustion(e);

664

665

} else if (e.isSyntaxError()) {

666

// Syntax error - user input issue

667

System.err.println("Please check your code syntax");

668

669

} else if (e.isHostException()) {

670

// Host exception - could be programming error

671

Throwable cause = e.asHostException();

672

if (cause instanceof SecurityException) {

673

SecurityLogger.logSecurityViolation(e);

674

}

675

676

} else if (e.isInterrupted() || e.isCancelled()) {

677

// Execution control - expected behavior

678

System.out.println("Execution was controlled/cancelled");

679

}

680

}

681

}

682

}

683

684

// Usage with monitoring

685

public class MonitoredExecution {

686

public static void main(String[] args) {

687

// Setup comprehensive monitoring

688

Management management = Management.newBuilder().build();

689

ExecutionListener listener = management.newExecutionListener();

690

691

// Resource limits

692

ResourceLimits limits = ResourceLimits.newBuilder()

693

.statementLimit(10000, null)

694

.onLimit(event -> {

695

System.err.printf("Resource limit hit: %s (%d/%d)%n",

696

event.getLimitType(), event.getConsumed(), event.getLimit());

697

})

698

.build();

699

700

// Create monitored context

701

Context context = Context.newBuilder("js")

702

.resourceLimits(limits)

703

.build();

704

705

// Attach listener

706

listener.attach(context);

707

708

// Performance monitoring

709

listener.onEnter(event -> {

710

if (event.isRoot()) {

711

System.out.println("Starting execution of: " + event.getRootName());

712

}

713

});

714

715

listener.onReturn(event -> {

716

if (event.isRoot()) {

717

RuntimeException exception = event.getException();

718

if (exception != null) {

719

if (exception instanceof PolyglotException pe) {

720

PolyglotExceptionAnalyzer.analyzeException(pe);

721

}

722

} else {

723

Value returnValue = event.getReturnValue();

724

System.out.println("Execution completed: " +

725

(returnValue != null ? returnValue.toString() : "void"));

726

}

727

}

728

});

729

730

// Execute code with monitoring

731

String userCode = """

732

function complexCalculation(n) {

733

if (n <= 0) throw new Error('Invalid input');

734

let result = 1;

735

for (let i = 1; i <= n; i++) {

736

result *= i;

737

}

738

return result;

739

}

740

741

try {

742

complexCalculation(10);

743

} catch (e) {

744

console.error('Calculation failed:', e.message);

745

throw e;

746

}

747

""";

748

749

PolyglotExceptionAnalyzer.executeWithDetailedErrorHandling(context, userCode);

750

751

// Cleanup

752

listener.close();

753

context.close();

754

}

755

}

756

757

class SecurityLogger {

758

public static void logResourceExhaustion(PolyglotException e) {

759

System.err.println("[SECURITY] Resource exhaustion detected: " + e.getMessage());

760

}

761

762

public static void logSecurityViolation(PolyglotException e) {

763

System.err.println("[SECURITY] Security violation: " + e.getMessage());

764

}

765

}

766

```

767

768

## Performance Profiling

769

770

Combining execution listeners with resource monitoring provides comprehensive performance profiling capabilities.

771

772

### Execution Performance Profiler

773

774

```java

775

public class PolyglotProfiler {

776

private final Map<String, PerformanceMetrics> metrics = new ConcurrentHashMap<>();

777

private final AtomicLong globalStartTime = new AtomicLong();

778

779

public void startProfiling(Context context) {

780

Management management = Management.newBuilder().build();

781

ExecutionListener listener = management.newExecutionListener();

782

783

globalStartTime.set(System.nanoTime());

784

785

listener.onEnter(this::recordEntry);

786

listener.onReturn(this::recordExit);

787

listener.attach(context);

788

789

// Setup periodic reporting

790

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

791

scheduler.scheduleAtFixedRate(this::reportMetrics, 5, 5, TimeUnit.SECONDS);

792

}

793

794

private void recordEntry(ExecutionEvent event) {

795

String key = getEventKey(event);

796

if (key != null) {

797

PerformanceMetrics perf = metrics.computeIfAbsent(key,

798

k -> new PerformanceMetrics(k));

799

perf.recordEntry();

800

}

801

}

802

803

private void recordExit(ExecutionEvent event) {

804

String key = getEventKey(event);

805

if (key != null) {

806

PerformanceMetrics perf = metrics.get(key);

807

if (perf != null) {

808

perf.recordExit(event.getException() != null);

809

}

810

}

811

}

812

813

private String getEventKey(ExecutionEvent event) {

814

if (event.isRoot() && event.getRootName() != null) {

815

return event.getRootName();

816

}

817

return null;

818

}

819

820

public void reportMetrics() {

821

long totalTime = System.nanoTime() - globalStartTime.get();

822

823

System.out.printf("\n=== Performance Report (Total: %.2f ms) ===%n",

824

totalTime / 1_000_000.0);

825

826

metrics.values().stream()

827

.sorted((a, b) -> Long.compare(b.getTotalTime(), a.getTotalTime()))

828

.limit(10) // Top 10 functions

829

.forEach(this::printMetrics);

830

}

831

832

private void printMetrics(PerformanceMetrics metrics) {

833

System.out.printf("%-20s | Calls: %5d | Total: %8.2f ms | Avg: %6.2f ms | Errors: %3d%n",

834

metrics.getName(),

835

metrics.getCallCount(),

836

metrics.getTotalTime() / 1_000_000.0,

837

metrics.getAverageTime() / 1_000_000.0,

838

metrics.getErrorCount());

839

}

840

}

841

842

class PerformanceMetrics {

843

private final String name;

844

private final AtomicLong callCount = new AtomicLong(0);

845

private final AtomicLong totalTime = new AtomicLong(0);

846

private final AtomicLong errorCount = new AtomicLong(0);

847

private volatile long entryTime;

848

849

public PerformanceMetrics(String name) {

850

this.name = name;

851

}

852

853

public void recordEntry() {

854

callCount.incrementAndGet();

855

entryTime = System.nanoTime();

856

}

857

858

public void recordExit(boolean hasError) {

859

long duration = System.nanoTime() - entryTime;

860

totalTime.addAndGet(duration);

861

862

if (hasError) {

863

errorCount.incrementAndGet();

864

}

865

}

866

867

public String getName() { return name; }

868

public long getCallCount() { return callCount.get(); }

869

public long getTotalTime() { return totalTime.get(); }

870

public long getErrorCount() { return errorCount.get(); }

871

872

public long getAverageTime() {

873

long count = callCount.get();

874

return count > 0 ? totalTime.get() / count : 0;

875

}

876

}

877

```

878

879

## Monitoring Best Practices

880

881

### 1. Selective Monitoring

882

883

```java

884

// Monitor only user code, not internal operations

885

ExecutionListener listener = management.newExecutionListener();

886

listener.onEnter(event -> {

887

SourceSection location = event.getSourceLocation();

888

if (location != null && !location.getSource().isInternal()) {

889

// Process only user code events

890

monitorUserExecution(event);

891

}

892

});

893

```

894

895

### 2. Asynchronous Logging

896

897

```java

898

// Use async logging to minimize performance impact

899

ExecutorService logExecutor = Executors.newSingleThreadExecutor();

900

901

listener.onReturn(event -> {

902

// Capture data quickly

903

ExecutionEventData data = new ExecutionEventData(event);

904

905

// Process asynchronously

906

logExecutor.submit(() -> processEventData(data));

907

});

908

```

909

910

### 3. Sampling for High-Frequency Events

911

912

```java

913

// Sample high-frequency events to reduce overhead

914

AtomicLong eventCounter = new AtomicLong(0);

915

916

listener.onEnter(event -> {

917

long count = eventCounter.incrementAndGet();

918

if (count % 100 == 0) { // Sample every 100th event

919

recordSampledEvent(event);

920

}

921

});

922

```