xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/Metrics.java (revision 5d9f3aa0ca3da3a714233f987fa732f62c0965f6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
22  */
23 package org.opengrok.indexer;
24 
25 import io.micrometer.core.instrument.Clock;
26 import io.micrometer.core.instrument.MeterRegistry;
27 import io.micrometer.core.instrument.Tag;
28 import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;
29 import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;
30 import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
31 import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;
32 import io.micrometer.core.instrument.binder.system.ProcessorMetrics;
33 import io.micrometer.prometheus.PrometheusConfig;
34 import io.micrometer.prometheus.PrometheusMeterRegistry;
35 import io.micrometer.statsd.StatsdConfig;
36 import io.micrometer.statsd.StatsdMeterRegistry;
37 import io.micrometer.statsd.StatsdFlavor;
38 import org.opengrok.indexer.configuration.RuntimeEnvironment;
39 import org.opengrok.indexer.index.Indexer;
40 import org.opengrok.indexer.logger.LoggerFactory;
41 
42 import java.util.Collections;
43 import java.util.List;
44 import java.util.logging.Level;
45 import java.util.logging.Logger;
46 import java.util.stream.Collectors;
47 
48 /**
49  * Encapsulates logic of meter registry setup and handling.
50  * Generally, the web application publishes metrics to Prometheus and the Indexer to StatsD.
51  */
52 public final class Metrics {
53 
54     private static final Logger LOGGER = LoggerFactory.getLogger(Metrics.class);
55 
56     private static final StatsdConfig statsdConfig = new StatsdConfig() {
57         @Override
58         public String get(String k) {
59             return null;
60         }
61 
62         @Override
63         public StatsdFlavor flavor() {
64             return RuntimeEnvironment.getInstance().getStatsdConfig().getFlavor();
65         }
66 
67         @Override
68         public int port() {
69             return RuntimeEnvironment.getInstance().getStatsdConfig().getPort();
70         }
71 
72         @Override
73         public String host() {
74             return RuntimeEnvironment.getInstance().getStatsdConfig().getHost();
75         }
76 
77         @Override
78         public boolean buffered() {
79             return true;
80         }
81     };
82 
83     private static PrometheusMeterRegistry prometheusRegistry;
84     private static StatsdMeterRegistry statsdRegistry;
85 
86     static {
87         MeterRegistry registry = null;
88 
89         if (RuntimeEnvironment.getInstance().getStatsdConfig().isEnabled()) {
LOGGER.log(Level.INFO, "configuring StatsdRegistry")90             LOGGER.log(Level.INFO, "configuring StatsdRegistry");
91             statsdRegistry = new StatsdMeterRegistry(statsdConfig, Clock.SYSTEM);
92             registry = statsdRegistry;
93         } else if (!RuntimeEnvironment.getInstance().isIndexer()) {
LOGGER.log(Level.INFO, "configuring PrometheusRegistry")94             LOGGER.log(Level.INFO, "configuring PrometheusRegistry");
95             prometheusRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
96             registry = prometheusRegistry;
97         }
98 
99         if (registry != null) {
100             new ClassLoaderMetrics().bindTo(registry);
101             new JvmMemoryMetrics().bindTo(registry);
102             new JvmGcMetrics().bindTo(registry);
103             new ProcessorMetrics().bindTo(registry);
104             new JvmThreadMetrics().bindTo(registry);
105         }
106     }
107 
Metrics()108     private Metrics() {
109     }
110 
updateSubFiles(List<String> subFiles)111     public static void updateSubFiles(List<String> subFiles) {
112         // Add tag for per-project reindex.
113         if (statsdRegistry != null && !subFiles.isEmpty()) {
114             String projects = subFiles.stream().
115                     map(s -> s.startsWith(Indexer.PATH_SEPARATOR_STRING) ? s.substring(1) : s).
116                     collect(Collectors.joining(","));
117             Tag commonTag = Tag.of("projects", projects);
118             LOGGER.log(Level.FINE, "updating statsdRegistry with common tag: {}", commonTag);
119             statsdRegistry.config().commonTags(Collections.singleton(commonTag));
120         }
121     }
122 
getPrometheusRegistry()123     public static PrometheusMeterRegistry getPrometheusRegistry() {
124         return prometheusRegistry;
125     }
126 
getStatsdRegistry()127     private static StatsdMeterRegistry getStatsdRegistry() {
128         return statsdRegistry;
129     }
130 
131     /**
132      * Get registry based on running context.
133      * @return MeterRegistry instance
134      */
getRegistry()135     public static MeterRegistry getRegistry() {
136         if (RuntimeEnvironment.getInstance().isIndexer()) {
137             return getStatsdRegistry();
138         } else {
139             return getPrometheusRegistry();
140         }
141     }
142 }
143