aboutsummaryrefslogtreecommitdiffstats
path: root/configserver/src/main/java/com/yahoo/vespa/config/server/monitoring/Metrics.java
blob: ad86a4b436a1503b4c52abb50b5353c76d3d51c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.monitoring;

import com.yahoo.component.annotation.Inject;
import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.component.AbstractComponent;
import com.yahoo.concurrent.DaemonThreadFactory;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
import com.yahoo.container.jdisc.config.HealthMonitorConfig;
import com.yahoo.docproc.jdisc.metric.NullMetric;
import com.yahoo.jdisc.Metric;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Metrics for config server.
 *
 * @author Harald Musum
 */
public class Metrics extends AbstractComponent implements MetricUpdaterFactory, Runnable {

    private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(Metrics.class.getName());
    private static final String METRIC_REQUESTS = getMetricName("requests");
    private static final String METRIC_FAILED_REQUESTS = getMetricName("failedRequests");
    private static final String METRIC_FREE_MEMORY = getMetricName("freeMemory");
    private static final String METRIC_LATENCY = getMetricName("latency");

    private final Metric metric;
    private final Optional<ZKMetricUpdater> zkMetricUpdater;

    // TODO The map is the key for now
    private final Map<Map<String, String>, MetricUpdater> metricUpdaters = new ConcurrentHashMap<>();
    private final Optional<ScheduledExecutorService> executorService;

    @Inject
    public Metrics(Metric metric, HealthMonitorConfig healthMonitorConfig, ZookeeperServerConfig zkServerConfig) {
        this(metric, healthMonitorConfig, zkServerConfig, true);
    }

    private Metrics(Metric metric, HealthMonitorConfig healthMonitorConfig,
                    ZookeeperServerConfig zkServerConfig, boolean createZkMetricUpdater) {
        this.metric = metric;

        if (createZkMetricUpdater) {
            log.log(Level.FINE, () -> "Metric update interval is " + healthMonitorConfig.snapshot_interval() + " seconds");
            long intervalMs = (long) (healthMonitorConfig.snapshot_interval() * 1000);
            executorService = Optional.of(new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory("configserver-metrics")));
            executorService.get().scheduleAtFixedRate(this, 20000, intervalMs, TimeUnit.MILLISECONDS);
            zkMetricUpdater = Optional.of(new ZKMetricUpdater(zkServerConfig, 19500, intervalMs));
        } else {
            executorService = Optional.empty();
            zkMetricUpdater = Optional.empty();
        }
    }

    public static Metrics createTestMetrics() {
        NullMetric metric = new NullMetric();
        HealthMonitorConfig.Builder builder = new HealthMonitorConfig.Builder();
        builder.snapshot_interval(60.0);
        ZookeeperServerConfig.Builder zkBuilder = new ZookeeperServerConfig.Builder().myid(1);
        return new Metrics(metric, new HealthMonitorConfig(builder), new ZookeeperServerConfig(zkBuilder), false);
    }

    void incrementRequests(Metric.Context metricContext) {
        metric.add(METRIC_REQUESTS, 1, metricContext);
    }

    void incrementFailedRequests(Metric.Context metricContext) {
        metric.add(METRIC_FAILED_REQUESTS, 1, metricContext);
    }

    void incrementProcTime(long increment, Metric.Context metricContext) {
        metric.set(METRIC_LATENCY, increment, metricContext);
    }

    public Metric getMetric() {
        return metric;
    }

    public MetricUpdater removeMetricUpdater(Map<String, String> dimensions) {
        return metricUpdaters.remove(dimensions);
    }

    public static Map<String, String> createDimensions(ApplicationId applicationId) {
        final Map<String, String> properties = new LinkedHashMap<>();
        properties.put("tenantName", applicationId.tenant().value());
        properties.put("applicationName", applicationId.application().value());
        properties.put("applicationInstance", applicationId.instance().value());
        return properties;
    }

    public static Map<String, String> createDimensions(TenantName tenant) {
        final Map<String, String> properties = new LinkedHashMap<>();
        properties.put("tenantName", tenant.value());
        return properties;
    }

    public synchronized MetricUpdater getOrCreateMetricUpdater(Map<String, String> dimensions) {
        if (metricUpdaters.containsKey(dimensions)) {
            return metricUpdaters.get(dimensions);
        }
        MetricUpdater metricUpdater = new MetricUpdater(this, dimensions);
        metricUpdaters.put(dimensions, metricUpdater);
        return metricUpdater;
    }

    @Override
    public void run() {
        for (MetricUpdater metricUpdater : metricUpdaters.values()) {
            log.log(Level.FINE, () -> "Running metric updater for static values for " + metricUpdater.getDimensions());
            for (Map.Entry<String, Number> fixedMetric : metricUpdater.getStaticMetrics().entrySet()) {
                log.log(Level.FINE, () -> "Setting " + fixedMetric.getKey());
                metric.set(fixedMetric.getKey(), fixedMetric.getValue(), metricUpdater.getMetricContext());
            }
        }
        setRegularMetrics();
        zkMetricUpdater.ifPresent(updater -> updater.getZKMetrics().forEach((attr, val) -> metric.set(attr, val, null)));
    }

    public void deconstruct() {
        executorService.ifPresent(ExecutorService::shutdown);
        zkMetricUpdater.ifPresent(ZKMetricUpdater::shutdown);
    }

    private void setRegularMetrics() {
        metric.set(METRIC_FREE_MEMORY, Runtime.getRuntime().freeMemory(), null);
    }

    void increment(String metricName, Metric.Context context) {
        metric.add(metricName, 1, context);
    }

    void set(String metricName, Number value, Metric.Context context) {
        metric.set(metricName, value, context);
    }

    static String getMetricName(String name) {
        return "configserver." + name;
    }
}