0
# Monitoring and Metrics
1
2
Phoenix provides comprehensive monitoring and metrics collection capabilities to track query performance, resource usage, and system health. The monitoring framework enables detailed analysis of Phoenix operations and supports performance optimization efforts.
3
4
## Core Imports
5
6
```java
7
import org.apache.phoenix.monitoring.*;
8
import org.apache.phoenix.jdbc.*;
9
import java.util.Map;
10
import java.util.concurrent.TimeUnit;
11
```
12
13
## Metric Types
14
15
### MetricType
16
17
Enumeration of all Phoenix metric types with detailed performance and resource monitoring.
18
19
```java{ .api }
20
public enum MetricType {
21
// Query performance metrics
22
QUERY_TIME("Query execution time", true),
23
QUERY_TIMEOUT("Query timeout occurrences", false),
24
QUERY_FAILED("Failed query count", false),
25
QUERY_EXECUTED("Executed query count", false),
26
27
// Scan metrics
28
SCAN_BYTES("Bytes scanned", true),
29
SCAN_ROWS("Rows scanned", true),
30
SCAN_TIME("Scan execution time", true),
31
32
// Memory metrics
33
MEMORY_CHUNK_BYTES("Memory chunk size in bytes", true),
34
MEMORY_WAIT_TIME("Memory wait time", true),
35
SPOOL_FILE_SIZE("Spool file size", true),
36
SPOOL_FILE_COUNTER("Number of spool files", false),
37
38
// Network and RPC metrics
39
BYTES_RECEIVED("Bytes received over network", true),
40
BYTES_SENT("Bytes sent over network", true),
41
RPC_TIME("RPC call time", true),
42
RPC_CALLS("Number of RPC calls", false),
43
44
// Cache metrics
45
CACHE_REFRESH_SPLITS_COUNTER("Cache refresh splits", false),
46
METADATA_CACHE_MISS_COUNTER("Metadata cache misses", false),
47
METADATA_CACHE_HIT_COUNTER("Metadata cache hits", false),
48
49
// Mutation metrics
50
MUTATION_BATCH_SIZE("Mutation batch size", true),
51
MUTATION_COMMIT_TIME("Mutation commit time", true),
52
MUTATION_BYTES("Mutation data size", true),
53
54
// Connection metrics
55
OPEN_PHOENIX_CONNECTIONS("Open Phoenix connections", false),
56
QUERY_SERVICES_COUNTER("Query services operations", false),
57
HCONNECTIONS_COUNTER("HBase connections", false);
58
59
private final String description;
60
private final boolean isTimeMetric;
61
62
MetricType(String description, boolean isTimeMetric) {
63
this.description = description;
64
this.isTimeMetric = isTimeMetric;
65
}
66
67
public String getDescription()
68
public String getMetricName()
69
public boolean isTimer()
70
public boolean isHistogram()
71
public boolean isCounter()
72
}
73
```
74
75
**Usage:**
76
```java
77
// Access metric information
78
for (MetricType metricType : MetricType.values()) {
79
System.out.println("Metric: " + metricType.getMetricName());
80
System.out.println("Description: " + metricType.getDescription());
81
System.out.println("Is Timer: " + metricType.isTimer());
82
System.out.println("Is Counter: " + metricType.isCounter());
83
System.out.println();
84
}
85
86
// Check specific metric properties
87
MetricType queryTime = MetricType.QUERY_TIME;
88
if (queryTime.isTimer()) {
89
System.out.println("Query time is measured as a timer metric");
90
}
91
92
MetricType queryCount = MetricType.QUERY_EXECUTED;
93
if (queryCount.isCounter()) {
94
System.out.println("Query executed is a counter metric");
95
}
96
```
97
98
## Global Client Metrics
99
100
### GlobalClientMetrics
101
102
Global client-side metrics collection providing system-wide monitoring.
103
104
```java{ .api }
105
public class GlobalClientMetrics {
106
// Global metric instances
107
public static final GlobalMetric GLOBAL_QUERY_TIME =
108
GlobalClientMetrics.getInstance(MetricType.QUERY_TIME);
109
public static final GlobalMetric GLOBAL_SCAN_BYTES =
110
GlobalClientMetrics.getInstance(MetricType.SCAN_BYTES);
111
public static final GlobalMetric GLOBAL_MEMORY_CHUNK_BYTES =
112
GlobalClientMetrics.getInstance(MetricType.MEMORY_CHUNK_BYTES);
113
public static final GlobalMetric GLOBAL_MUTATION_BATCH_SIZE =
114
GlobalClientMetrics.getInstance(MetricType.MUTATION_BATCH_SIZE);
115
116
// Metric factory methods
117
public static GlobalMetric getInstance(MetricType metricType)
118
public static boolean isMetricsEnabled()
119
public static void setMetricsEnabled(boolean enabled)
120
121
// Metric collection methods
122
public static Map<MetricType, Long> getGlobalMetrics()
123
public static long getGlobalMetricValue(MetricType metricType)
124
public static void resetGlobalMetrics()
125
126
// Metric aggregation
127
public static Map<String, Object> getMetricsSummary()
128
public static String getMetricsReport()
129
}
130
```
131
132
### GlobalMetric
133
134
Individual global metric implementation with thread-safe operations.
135
136
```java{ .api }
137
public class GlobalMetric {
138
// Metric operations
139
public void increment()
140
public void increment(long delta)
141
public void update(long value)
142
public void decrement()
143
public void decrement(long delta)
144
145
// Metric queries
146
public long getValue()
147
public long getCount()
148
public double getMean()
149
public long getMax()
150
public long getMin()
151
152
// Reset operations
153
public void reset()
154
public MetricType getMetricType()
155
}
156
```
157
158
**Usage:**
159
```java
160
// Enable global metrics collection
161
GlobalClientMetrics.setMetricsEnabled(true);
162
163
// Use global metrics during operations
164
Connection connection = DriverManager.getConnection(url);
165
Statement stmt = connection.createStatement();
166
167
// Query execution automatically updates metrics
168
long startTime = System.currentTimeMillis();
169
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM large_table");
170
171
// Access global metrics
172
long totalQueryTime = GlobalClientMetrics.GLOBAL_QUERY_TIME.getValue();
173
long totalScanBytes = GlobalClientMetrics.GLOBAL_SCAN_BYTES.getValue();
174
175
System.out.println("Total query time across all queries: " + totalQueryTime + "ms");
176
System.out.println("Total bytes scanned: " + totalScanBytes);
177
178
// Get comprehensive metrics summary
179
Map<String, Object> summary = GlobalClientMetrics.getMetricsSummary();
180
for (Map.Entry<String, Object> entry : summary.entrySet()) {
181
System.out.println(entry.getKey() + ": " + entry.getValue());
182
}
183
184
// Generate metrics report
185
String report = GlobalClientMetrics.getMetricsReport();
186
System.out.println("=== Phoenix Metrics Report ===");
187
System.out.println(report);
188
189
// Reset metrics for new measurement period
190
GlobalClientMetrics.resetGlobalMetrics();
191
```
192
193
## Table-Level Metrics
194
195
### TableMetricsManager
196
197
Manages metrics collection for individual Phoenix tables.
198
199
```java{ .api }
200
public class TableMetricsManager {
201
// Singleton access
202
public static TableMetricsManager getInstance()
203
204
// Table metrics management
205
public TableClientMetrics getTableMetrics(String tableName)
206
public void updateTableMetrics(String tableName, MetricType metricType, long value)
207
public void resetTableMetrics(String tableName)
208
public void removeTableMetrics(String tableName)
209
210
// Bulk operations
211
public Map<String, TableClientMetrics> getAllTableMetrics()
212
public void resetAllTableMetrics()
213
public int getTrackedTableCount()
214
215
// Configuration
216
public void setMaxTrackedTables(int maxTables)
217
public boolean isTableMetricsEnabled()
218
public void setTableMetricsEnabled(boolean enabled)
219
}
220
```
221
222
### TableClientMetrics
223
224
Client-side metrics for individual Phoenix tables.
225
226
```java{ .api }
227
public class TableClientMetrics {
228
// Constructor
229
public TableClientMetrics(String tableName)
230
231
// Metric operations
232
public void incrementMetric(MetricType metricType)
233
public void incrementMetric(MetricType metricType, long delta)
234
public void updateMetric(MetricType metricType, long value)
235
236
// Metric queries
237
public long getMetricValue(MetricType metricType)
238
public Map<MetricType, Long> getAllMetrics()
239
public String getTableName()
240
241
// Statistics
242
public long getTotalQueryTime()
243
public long getTotalScanBytes()
244
public long getQueryCount()
245
public double getAverageQueryTime()
246
247
// Reset operations
248
public void reset()
249
public void resetMetric(MetricType metricType)
250
}
251
```
252
253
**Usage:**
254
```java
255
// Enable table-level metrics
256
TableMetricsManager manager = TableMetricsManager.getInstance();
257
manager.setTableMetricsEnabled(true);
258
manager.setMaxTrackedTables(100);
259
260
// Execute queries on specific tables
261
String tableName = "users";
262
Connection connection = DriverManager.getConnection(url);
263
264
// Table metrics are automatically collected during query execution
265
Statement stmt = connection.createStatement();
266
ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName + " WHERE age > 25");
267
268
// Process results...
269
while (rs.next()) {
270
// Result processing
271
}
272
273
// Access table-specific metrics
274
TableClientMetrics tableMetrics = manager.getTableMetrics(tableName);
275
long queryTime = tableMetrics.getMetricValue(MetricType.QUERY_TIME);
276
long scanBytes = tableMetrics.getMetricValue(MetricType.SCAN_BYTES);
277
long queryCount = tableMetrics.getQueryCount();
278
double avgQueryTime = tableMetrics.getAverageQueryTime();
279
280
System.out.println("Table: " + tableName);
281
System.out.println("Total query time: " + queryTime + "ms");
282
System.out.println("Total scan bytes: " + scanBytes);
283
System.out.println("Query count: " + queryCount);
284
System.out.println("Average query time: " + String.format("%.2f", avgQueryTime) + "ms");
285
286
// Get metrics for all tables
287
Map<String, TableClientMetrics> allMetrics = manager.getAllTableMetrics();
288
for (Map.Entry<String, TableClientMetrics> entry : allMetrics.entrySet()) {
289
String table = entry.getKey();
290
TableClientMetrics metrics = entry.getValue();
291
292
System.out.println("\n=== Metrics for table: " + table + " ===");
293
Map<MetricType, Long> tableMetricValues = metrics.getAllMetrics();
294
295
for (Map.Entry<MetricType, Long> metricEntry : tableMetricValues.entrySet()) {
296
System.out.println(metricEntry.getKey().getMetricName() + ": " + metricEntry.getValue());
297
}
298
}
299
300
// Reset metrics for specific table
301
manager.resetTableMetrics(tableName);
302
```
303
304
## Query-Level Monitoring
305
306
### PhoenixMonitoredConnection
307
308
Connection interface providing access to metrics and monitoring information.
309
310
```java{ .api }
311
public interface PhoenixMonitoredConnection extends Connection {
312
// Metrics access
313
ReadMetricQueue getReadMetricsQueue()
314
WriteMetricQueue getWriteMetricsQueue()
315
OverAllQueryMetrics getOverallQueryMetrics()
316
317
// Query monitoring
318
QueryLogger getQueryLogger()
319
void enableQueryLogging(boolean enable)
320
boolean isQueryLoggingEnabled()
321
322
// Connection metrics
323
ConnectionMetrics getConnectionMetrics()
324
}
325
```
326
327
### ReadMetricQueue
328
329
Queue for collecting read operation metrics during query execution.
330
331
```java{ .api }
332
public class ReadMetricQueue {
333
// Queue operations
334
public void addMetric(ReadMetric metric)
335
public ReadMetric pollMetric()
336
public List<ReadMetric> drainMetrics()
337
338
// Queue state
339
public int size()
340
public boolean isEmpty()
341
public void clear()
342
343
// Aggregated metrics
344
public long getTotalReadTime()
345
public long getTotalBytesRead()
346
public long getTotalRowsRead()
347
public int getReadOperationCount()
348
}
349
```
350
351
### WriteMetricQueue
352
353
Queue for collecting write operation metrics during mutation execution.
354
355
```java{ .api }
356
public class WriteMetricQueue {
357
// Queue operations
358
public void addMetric(WriteMetric metric)
359
public WriteMetric pollMetric()
360
public List<WriteMetric> drainMetrics()
361
362
// Queue state
363
public int size()
364
public boolean isEmpty()
365
public void clear()
366
367
// Aggregated metrics
368
public long getTotalWriteTime()
369
public long getTotalBytesWritten()
370
public long getTotalRowsWritten()
371
public int getWriteOperationCount()
372
}
373
```
374
375
**Usage:**
376
```java
377
// Access query-level monitoring
378
PhoenixConnection phoenixConn = connection.unwrap(PhoenixConnection.class);
379
PhoenixMonitoredConnection monitoredConn = (PhoenixMonitoredConnection) phoenixConn;
380
381
// Enable query logging
382
monitoredConn.enableQueryLogging(true);
383
384
// Execute monitored query
385
Statement stmt = connection.createStatement();
386
ResultSet rs = stmt.executeQuery("SELECT * FROM orders WHERE order_date > '2023-01-01'");
387
388
// Process results
389
int rowCount = 0;
390
while (rs.next()) {
391
rowCount++;
392
}
393
394
// Access read metrics
395
ReadMetricQueue readMetrics = monitoredConn.getReadMetricsQueue();
396
System.out.println("Read operations: " + readMetrics.getReadOperationCount());
397
System.out.println("Total read time: " + readMetrics.getTotalReadTime() + "ms");
398
System.out.println("Total bytes read: " + readMetrics.getTotalBytesRead());
399
System.out.println("Total rows read: " + readMetrics.getTotalRowsRead());
400
401
// Drain metrics for processing
402
List<ReadMetric> allReadMetrics = readMetrics.drainMetrics();
403
for (ReadMetric metric : allReadMetrics) {
404
System.out.println("Read operation: " + metric.toString());
405
}
406
407
// For write operations
408
PreparedStatement pstmt = connection.prepareStatement("UPSERT INTO orders VALUES (?, ?, ?)");
409
for (int i = 0; i < 1000; i++) {
410
pstmt.setLong(1, i);
411
pstmt.setString(2, "Product " + i);
412
pstmt.setBigDecimal(3, new BigDecimal(Math.random() * 1000));
413
pstmt.executeUpdate();
414
}
415
connection.commit();
416
417
// Access write metrics
418
WriteMetricQueue writeMetrics = monitoredConn.getWriteMetricsQueue();
419
System.out.println("Write operations: " + writeMetrics.getWriteOperationCount());
420
System.out.println("Total write time: " + writeMetrics.getTotalWriteTime() + "ms");
421
System.out.println("Total bytes written: " + writeMetrics.getTotalBytesWritten());
422
System.out.println("Total rows written: " + writeMetrics.getTotalRowsWritten());
423
```
424
425
## Custom Monitoring Implementation
426
427
### MetricsCollector
428
429
Custom metrics collection and reporting system.
430
431
```java
432
// Custom metrics collector for Phoenix operations
433
public class PhoenixMetricsCollector {
434
private final Map<String, QueryMetrics> queryMetrics = new ConcurrentHashMap<>();
435
private final TableMetricsManager tableManager = TableMetricsManager.getInstance();
436
private final ExecutorService reportingExecutor = Executors.newSingleThreadExecutor();
437
438
public void startMetricsCollection() {
439
// Enable all metrics
440
GlobalClientMetrics.setMetricsEnabled(true);
441
tableManager.setTableMetricsEnabled(true);
442
443
// Start periodic reporting
444
reportingExecutor.submit(this::periodicReporting);
445
}
446
447
public void recordQueryStart(String queryId, String sql, String tableName) {
448
QueryMetrics metrics = new QueryMetrics(queryId, sql, tableName);
449
metrics.setStartTime(System.currentTimeMillis());
450
queryMetrics.put(queryId, metrics);
451
}
452
453
public void recordQueryEnd(String queryId, int rowCount, boolean success) {
454
QueryMetrics metrics = queryMetrics.get(queryId);
455
if (metrics != null) {
456
metrics.setEndTime(System.currentTimeMillis());
457
metrics.setRowCount(rowCount);
458
metrics.setSuccess(success);
459
460
// Update table metrics
461
if (success) {
462
String tableName = metrics.getTableName();
463
long executionTime = metrics.getExecutionTime();
464
tableManager.updateTableMetrics(tableName, MetricType.QUERY_TIME, executionTime);
465
tableManager.updateTableMetrics(tableName, MetricType.QUERY_EXECUTED, 1);
466
} else {
467
tableManager.updateTableMetrics(metrics.getTableName(), MetricType.QUERY_FAILED, 1);
468
}
469
}
470
}
471
472
public void recordSlowQuery(String queryId, long thresholdMs) {
473
QueryMetrics metrics = queryMetrics.get(queryId);
474
if (metrics != null && metrics.getExecutionTime() > thresholdMs) {
475
System.out.println("SLOW QUERY DETECTED:");
476
System.out.println("Query ID: " + queryId);
477
System.out.println("Execution time: " + metrics.getExecutionTime() + "ms");
478
System.out.println("SQL: " + metrics.getSql());
479
System.out.println("Table: " + metrics.getTableName());
480
}
481
}
482
483
public MetricsSummary generateSummary() {
484
MetricsSummary summary = new MetricsSummary();
485
486
// Global metrics
487
Map<MetricType, Long> globalMetrics = GlobalClientMetrics.getGlobalMetrics();
488
summary.setGlobalMetrics(globalMetrics);
489
490
// Table metrics
491
Map<String, TableClientMetrics> allTableMetrics = tableManager.getAllTableMetrics();
492
summary.setTableMetrics(allTableMetrics);
493
494
// Query metrics
495
summary.setQueryMetrics(new HashMap<>(queryMetrics));
496
497
return summary;
498
}
499
500
private void periodicReporting() {
501
try {
502
while (!Thread.currentThread().isInterrupted()) {
503
Thread.sleep(60000); // Report every minute
504
505
MetricsSummary summary = generateSummary();
506
generateReport(summary);
507
508
// Clean up old query metrics (keep last hour)
509
cleanupOldMetrics();
510
}
511
} catch (InterruptedException e) {
512
Thread.currentThread().interrupt();
513
}
514
}
515
516
private void generateReport(MetricsSummary summary) {
517
System.out.println("\n=== Phoenix Metrics Report ===");
518
System.out.println("Report time: " + new Date());
519
520
// Global metrics report
521
Map<MetricType, Long> globalMetrics = summary.getGlobalMetrics();
522
System.out.println("\n--- Global Metrics ---");
523
for (Map.Entry<MetricType, Long> entry : globalMetrics.entrySet()) {
524
if (entry.getValue() > 0) {
525
System.out.println(entry.getKey().getDescription() + ": " + entry.getValue());
526
}
527
}
528
529
// Table metrics report
530
Map<String, TableClientMetrics> tableMetrics = summary.getTableMetrics();
531
System.out.println("\n--- Table Metrics ---");
532
for (Map.Entry<String, TableClientMetrics> entry : tableMetrics.entrySet()) {
533
String tableName = entry.getKey();
534
TableClientMetrics metrics = entry.getValue();
535
536
System.out.println("Table: " + tableName);
537
System.out.println(" Query count: " + metrics.getQueryCount());
538
System.out.println(" Average query time: " +
539
String.format("%.2f", metrics.getAverageQueryTime()) + "ms");
540
System.out.println(" Total scan bytes: " +
541
formatBytes(metrics.getMetricValue(MetricType.SCAN_BYTES)));
542
}
543
544
// Recent slow queries
545
System.out.println("\n--- Recent Slow Queries (>5s) ---");
546
long currentTime = System.currentTimeMillis();
547
int slowQueryCount = 0;
548
549
for (QueryMetrics queryMetrics : summary.getQueryMetrics().values()) {
550
if (queryMetrics.getExecutionTime() > 5000 &&
551
(currentTime - queryMetrics.getStartTime()) < 300000) { // Last 5 minutes
552
System.out.println("Query: " + queryMetrics.getQueryId());
553
System.out.println(" Time: " + queryMetrics.getExecutionTime() + "ms");
554
System.out.println(" Table: " + queryMetrics.getTableName());
555
System.out.println(" Rows: " + queryMetrics.getRowCount());
556
slowQueryCount++;
557
}
558
}
559
560
if (slowQueryCount == 0) {
561
System.out.println("No slow queries detected in the last 5 minutes.");
562
}
563
564
System.out.println("=== End Report ===\n");
565
}
566
567
private void cleanupOldMetrics() {
568
long cutoffTime = System.currentTimeMillis() - 3600000; // 1 hour ago
569
queryMetrics.entrySet().removeIf(entry ->
570
entry.getValue().getStartTime() < cutoffTime
571
);
572
}
573
574
private String formatBytes(long bytes) {
575
if (bytes < 1024) return bytes + " B";
576
if (bytes < 1024 * 1024) return String.format("%.2f KB", bytes / 1024.0);
577
if (bytes < 1024 * 1024 * 1024) return String.format("%.2f MB", bytes / (1024.0 * 1024.0));
578
return String.format("%.2f GB", bytes / (1024.0 * 1024.0 * 1024.0));
579
}
580
581
public void shutdown() {
582
reportingExecutor.shutdown();
583
try {
584
if (!reportingExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
585
reportingExecutor.shutdownNow();
586
}
587
} catch (InterruptedException e) {
588
reportingExecutor.shutdownNow();
589
Thread.currentThread().interrupt();
590
}
591
}
592
}
593
594
// Supporting classes
595
public class QueryMetrics {
596
private final String queryId;
597
private final String sql;
598
private final String tableName;
599
private long startTime;
600
private long endTime;
601
private int rowCount;
602
private boolean success;
603
604
public QueryMetrics(String queryId, String sql, String tableName) {
605
this.queryId = queryId;
606
this.sql = sql;
607
this.tableName = tableName;
608
}
609
610
public long getExecutionTime() {
611
return endTime - startTime;
612
}
613
614
// Getters and setters
615
public String getQueryId() { return queryId; }
616
public String getSql() { return sql; }
617
public String getTableName() { return tableName; }
618
public long getStartTime() { return startTime; }
619
public void setStartTime(long startTime) { this.startTime = startTime; }
620
public long getEndTime() { return endTime; }
621
public void setEndTime(long endTime) { this.endTime = endTime; }
622
public int getRowCount() { return rowCount; }
623
public void setRowCount(int rowCount) { this.rowCount = rowCount; }
624
public boolean isSuccess() { return success; }
625
public void setSuccess(boolean success) { this.success = success; }
626
}
627
628
public class MetricsSummary {
629
private Map<MetricType, Long> globalMetrics;
630
private Map<String, TableClientMetrics> tableMetrics;
631
private Map<String, QueryMetrics> queryMetrics;
632
633
// Getters and setters
634
public Map<MetricType, Long> getGlobalMetrics() { return globalMetrics; }
635
public void setGlobalMetrics(Map<MetricType, Long> globalMetrics) { this.globalMetrics = globalMetrics; }
636
public Map<String, TableClientMetrics> getTableMetrics() { return tableMetrics; }
637
public void setTableMetrics(Map<String, TableClientMetrics> tableMetrics) { this.tableMetrics = tableMetrics; }
638
public Map<String, QueryMetrics> getQueryMetrics() { return queryMetrics; }
639
public void setQueryMetrics(Map<String, QueryMetrics> queryMetrics) { this.queryMetrics = queryMetrics; }
640
}
641
```
642
643
### Usage Example
644
645
```java
646
// Integration with Phoenix application
647
public class MonitoredPhoenixApplication {
648
private final PhoenixMetricsCollector metricsCollector = new PhoenixMetricsCollector();
649
private final Connection connection;
650
651
public MonitoredPhoenixApplication(String phoenixUrl) throws SQLException {
652
this.connection = DriverManager.getConnection(phoenixUrl);
653
metricsCollector.startMetricsCollection();
654
}
655
656
public void executeQuery(String sql, String tableName) throws SQLException {
657
String queryId = UUID.randomUUID().toString();
658
659
// Record query start
660
metricsCollector.recordQueryStart(queryId, sql, tableName);
661
662
try {
663
Statement stmt = connection.createStatement();
664
ResultSet rs = stmt.executeQuery(sql);
665
666
int rowCount = 0;
667
while (rs.next()) {
668
rowCount++;
669
// Process row
670
}
671
672
// Record successful completion
673
metricsCollector.recordQueryEnd(queryId, rowCount, true);
674
675
// Check for slow queries
676
metricsCollector.recordSlowQuery(queryId, 1000); // 1 second threshold
677
678
rs.close();
679
stmt.close();
680
681
} catch (SQLException e) {
682
// Record failed query
683
metricsCollector.recordQueryEnd(queryId, 0, false);
684
throw e;
685
}
686
}
687
688
public void generateMetricsReport() {
689
MetricsSummary summary = metricsCollector.generateSummary();
690
// Process summary as needed
691
}
692
693
public void close() throws SQLException {
694
metricsCollector.shutdown();
695
connection.close();
696
}
697
698
public static void main(String[] args) throws SQLException {
699
MonitoredPhoenixApplication app = new MonitoredPhoenixApplication("jdbc:phoenix:localhost:2181");
700
701
try {
702
// Execute various queries
703
app.executeQuery("SELECT COUNT(*) FROM users", "users");
704
app.executeQuery("SELECT * FROM orders WHERE order_date > '2023-01-01'", "orders");
705
app.executeQuery("SELECT customer_id, SUM(amount) FROM transactions GROUP BY customer_id", "transactions");
706
707
// Generate report
708
app.generateMetricsReport();
709
710
} finally {
711
app.close();
712
}
713
}
714
}
715
```