3
3
import io .prometheus .client .Collector ;
4
4
import io .prometheus .client .CollectorRegistry ;
5
5
import io .prometheus .client .CounterMetricFamily ;
6
+ import io .prometheus .client .GaugeMetricFamily ;
6
7
import java .util .ArrayList ;
7
8
import java .util .Arrays ;
8
9
import java .util .Collections ;
32
33
* SessionFactory sessionFactory =
33
34
* entityManagerFactory.unwrap(SessionFactory.class);
34
35
* </pre>
36
+ * <p>
37
+ * When {@code enablePerQueryMetrics()} has been called, certain metrics like execution
38
+ * time are collected per query. This may create a lot of monitoring data, so it should
39
+ * be used with caution.
35
40
*
36
41
* @author Christian Kaltepoth
37
42
*/
38
43
public class HibernateStatisticsCollector extends Collector {
39
44
40
45
private static final List <String > LABEL_NAMES = Collections .singletonList ("unit" );
41
46
47
+ private static final List <String > LABEL_NAMES_PER_QUERY = Arrays .asList ("unit" , "query" );
48
+
42
49
private final Map <String , SessionFactory > sessionFactories = new ConcurrentHashMap <String , SessionFactory >();
43
50
51
+ private boolean perQueryMetricsEnabled ;
52
+
44
53
/**
45
54
* Creates an empty collector. If you use this constructor, you have to add one or more
46
55
* session factories to the collector by calling the {@link #add(SessionFactory, String)}
@@ -74,6 +83,19 @@ public HibernateStatisticsCollector add(SessionFactory sessionFactory, String na
74
83
return this ;
75
84
}
76
85
86
+ /**
87
+ * Enables collection of per-query metrics. Produces a lot of monitoring data, so use with caution.
88
+ * <p>
89
+ * Per-query metrics have a label "query" with the actual HQL query as value. The query will contain
90
+ * placeholders ("?") instead of the real parameter values (example: {@code select u from User u where id=?}).
91
+ *
92
+ * @return Returns the collector
93
+ */
94
+ public HibernateStatisticsCollector enablePerQueryMetrics () {
95
+ this .perQueryMetricsEnabled = true ;
96
+ return this ;
97
+ }
98
+
77
99
@ Override
78
100
public List <MetricFamilySamples > collect () {
79
101
List <MetricFamilySamples > metrics = new ArrayList <MetricFamilySamples >();
@@ -82,6 +104,9 @@ public List<MetricFamilySamples> collect() {
82
104
metrics .addAll (getCacheMetrics ());
83
105
metrics .addAll (getEntityMetrics ());
84
106
metrics .addAll (getQueryExecutionMetrics ());
107
+ if (perQueryMetricsEnabled ) {
108
+ metrics .addAll (getPerQueryMetrics ());
109
+ }
85
110
return metrics ;
86
111
}
87
112
@@ -448,25 +473,176 @@ public double getValue(Statistics statistics) {
448
473
);
449
474
}
450
475
476
+ private List <MetricFamilySamples > getPerQueryMetrics () {
477
+ List <MetricFamilySamples > metrics = new ArrayList <MetricFamilySamples >();
478
+
479
+ metrics .addAll (Arrays .asList (
480
+
481
+ createCounterForQuery ("hibernate_per_query_cache_hit_total" ,
482
+ "Global number of cache hits for query (getCacheHitCount)" ,
483
+ new ValueProviderPerQuery () {
484
+ @ Override
485
+ public double getValue (Statistics statistics , String query ) {
486
+ return statistics .getQueryStatistics (query )
487
+ .getCacheHitCount ();
488
+ }
489
+ }
490
+ ),
491
+ createCounterForQuery ("hibernate_per_query_cache_miss_total" ,
492
+ "Global number of cache misses for query (getCacheMissCount)" ,
493
+ new ValueProviderPerQuery () {
494
+ @ Override
495
+ public double getValue (Statistics statistics , String query ) {
496
+ return statistics .getQueryStatistics (query )
497
+ .getCacheMissCount ();
498
+ }
499
+ }
500
+ ),
501
+ createCounterForQuery ("hibernate_per_query_cache_put_total" ,
502
+ "Global number of cache puts for query (getCachePutCount)" ,
503
+ new ValueProviderPerQuery () {
504
+ @ Override
505
+ public double getValue (Statistics statistics , String query ) {
506
+ return statistics .getQueryStatistics (query )
507
+ .getCachePutCount ();
508
+ }
509
+ }
510
+ ),
511
+ createCounterForQuery ("hibernate_per_query_execution_total" ,
512
+ "Global number of executions for query (getExecutionCount)" ,
513
+ new ValueProviderPerQuery () {
514
+ @ Override
515
+ public double getValue (Statistics statistics , String query ) {
516
+ return statistics .getQueryStatistics (query )
517
+ .getExecutionCount ();
518
+ }
519
+ }
520
+ ),
521
+ createCounterForQuery ("hibernate_per_query_execution_rows_total" ,
522
+ "Global number of rows for all executions of query (getExecutionRowCount)" ,
523
+ new ValueProviderPerQuery () {
524
+ @ Override
525
+ public double getValue (Statistics statistics , String query ) {
526
+ return statistics .getQueryStatistics (query )
527
+ .getExecutionRowCount ();
528
+ }
529
+ }
530
+ ),
531
+ createGaugeForQuery ("hibernate_per_query_execution_min_seconds" ,
532
+ "Minimum execution time of query in seconds (based on getExecutionMinTime)" ,
533
+ new ValueProviderPerQuery () {
534
+ @ Override
535
+ public double getValue (Statistics statistics , String query ) {
536
+ return toSeconds (statistics .getQueryStatistics (query )
537
+ .getExecutionMinTime ());
538
+ }
539
+ }
540
+ ),
541
+ createGaugeForQuery ("hibernate_per_query_execution_max_seconds" ,
542
+ "Maximum execution time of query in seconds (based on getExecutionMaxTime)" ,
543
+ new ValueProviderPerQuery () {
544
+ @ Override
545
+ public double getValue (Statistics statistics , String query ) {
546
+ return toSeconds (statistics .getQueryStatistics (query )
547
+ .getExecutionMaxTime ());
548
+ }
549
+ }
550
+ ),
551
+ createCounterForQuery ("hibernate_per_query_execution_seconds_total" ,
552
+ "Accumulated execution time of query in seconds (based on getExecutionTotalTime)" ,
553
+ new ValueProviderPerQuery () {
554
+ @ Override
555
+ public double getValue (Statistics statistics , String query ) {
556
+ return toSeconds (statistics .getQueryStatistics (query )
557
+ .getExecutionTotalTime ());
558
+ }
559
+ }
560
+ )
561
+ ));
562
+
563
+ return metrics ;
564
+ }
565
+
451
566
private CounterMetricFamily createCounter (String metric , String help , ValueProvider provider ) {
452
567
453
568
CounterMetricFamily metricFamily = new CounterMetricFamily (metric , help , LABEL_NAMES );
454
569
455
570
for (Entry <String , SessionFactory > entry : sessionFactories .entrySet ()) {
456
571
metricFamily .addMetric (
457
- Collections .singletonList (entry .getKey ()),
458
- provider .getValue (entry .getValue ().getStatistics ())
572
+ Collections .singletonList (entry .getKey ()),
573
+ provider .getValue (entry .getValue ().getStatistics ())
459
574
);
460
575
}
461
576
462
577
return metricFamily ;
463
578
464
579
}
465
580
581
+ private CounterMetricFamily createCounterForQuery (String metric , String help , ValueProviderPerQuery provider ) {
582
+
583
+ final CounterMetricFamily counters = new CounterMetricFamily (metric , help , LABEL_NAMES_PER_QUERY );
584
+
585
+ addMetricsForQuery (new PerQuerySamples () {
586
+ @ Override
587
+ public void addMetric (List <String > labelValues , double value ) {
588
+ counters .addMetric (labelValues , value );
589
+ }
590
+ }, provider );
591
+
592
+ return counters ;
593
+
594
+ }
595
+
596
+ private GaugeMetricFamily createGaugeForQuery (String metric , String help , ValueProviderPerQuery provider ) {
597
+
598
+ final GaugeMetricFamily gauges = new GaugeMetricFamily (metric , help , LABEL_NAMES_PER_QUERY );
599
+
600
+ addMetricsForQuery (new PerQuerySamples () {
601
+ @ Override
602
+ public void addMetric (List <String > labelValues , double value ) {
603
+ gauges .addMetric (labelValues , value );
604
+ }
605
+ }, provider );
606
+
607
+ return gauges ;
608
+
609
+ }
610
+
611
+ private void addMetricsForQuery (PerQuerySamples samples , ValueProviderPerQuery provider ) {
612
+
613
+ for (Entry <String , SessionFactory > entry : sessionFactories .entrySet ()) {
614
+ SessionFactory sessionFactory = entry .getValue ();
615
+ Statistics stats = sessionFactory .getStatistics ();
616
+ String unitName = entry .getKey ();
617
+
618
+ for (String query : stats .getQueries ()) {
619
+ samples .addMetric (Arrays .asList (unitName , query ), provider .getValue (stats , query ));
620
+ }
621
+ }
622
+ }
623
+
624
+ private double toSeconds (long milliseconds ){
625
+ return milliseconds / 1000d ;
626
+ }
627
+
628
+ private interface PerQuerySamples {
629
+
630
+ void addMetric (List <String > labelValues , double value );
631
+
632
+ }
633
+
634
+
466
635
private interface ValueProvider {
467
636
468
637
double getValue (Statistics statistics );
469
638
470
639
}
471
640
641
+ private interface ValueProviderPerQuery {
642
+
643
+ double getValue (Statistics statistics , String query );
644
+
645
+ }
646
+
647
+
472
648
}
0 commit comments