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
```