aboutsummaryrefslogtreecommitdiffstats
path: root/storage/src/vespa/storage/storageserver/statereporter.cpp
blob: 8548590ea0b6e50bbc5a0b4e1de0bfbc049f6193 (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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "statereporter.h"
#include <vespa/storageframework/generic/clock/clock.h>
#include <vespa/metrics/jsonwriter.h>
#include <vespa/metrics/metricmanager.h>
#include <vespa/storage/common/nodestateupdater.h>
#include <vespa/vdslib/state/nodestate.h>
#include <vespa/vespalib/net/connection_auth_context.h>
#include <vespa/vespalib/stllike/asciistream.h>

#include <vespa/log/log.h>
LOG_SETUP(".status.statereporter");

namespace storage {

StateReporter::StateReporter(
        StorageComponentRegister& compReg,
        metrics::MetricManager& manager,
        ApplicationGenerationFetcher& generationFetcher,
        const std::string& name)
    : framework::StatusReporter("state", "State reporter"),
      _manager(manager),
      _metricsAdapter(manager),
      _stateApi(*this, *this, *this),
      _component(compReg, "statereporter"),
      _generationFetcher(generationFetcher),
      _name(name)
{
    LOG(debug, "Started state reporter");
    _component.registerStatusPage(*this);
}

StateReporter::~StateReporter() = default;

vespalib::string
StateReporter::getReportContentType(
        const framework::HttpUrlPath& /*path*/) const
{
    return "application/json";
}

namespace {

std::map<vespalib::string, vespalib::string>
getParams(const framework::HttpUrlPath &path)
{
    std::map<vespalib::string, vespalib::string> params = path.getAttributes();
    if (params.find("consumer") == params.end()) {
        params.insert(std::make_pair("consumer", "statereporter"));
    }
    return params;
}

}

bool
StateReporter::reportStatus(std::ostream& out,
                            const framework::HttpUrlPath& path) const
{
    // When we get here, capabilities have already been checked at a higher level, so
    // this will never fail unless a state API handler requires other capabilities than
    // we require for this reporter (in which case this will silently fail, but not
    // expose any other information).
    vespalib::net::ConnectionAuthContext dummy_ctx(vespalib::net::tls::PeerCredentials(), required_capabilities());
    auto status = _stateApi.get(path.getServerSpec(), path.getPath(), getParams(path), dummy_ctx);
    if (status.failed()) {
        LOG(debug, "State API reporting for path '%s' failed with status HTTP %d: %s",
            path.getPath().c_str(), status.status_code(), vespalib::string(status.status_message()).c_str());
        return false;
    }
    out << status.payload();
    return true;
}

vespalib::string
StateReporter::getMetrics(const vespalib::string &consumer)
{
    metrics::MetricLockGuard guard(_manager.getMetricLock());
    auto periods = _manager.getSnapshotPeriods(guard);
    if (periods.empty()) {
        return ""; // no configuration yet
    }
    auto interval = periods[0];

    // To get unset metrics, we have to copy active metrics, clear them
    // and then assign the snapshot
    metrics::MetricSnapshot snapshot(
            _manager.getMetricSnapshot(guard, interval).getName(), interval,
            _manager.getActiveMetrics(guard).getMetrics(), true);

    snapshot.reset();
    _manager.getMetricSnapshot(guard, interval).addToSnapshot(snapshot, _component.getClock().getSystemTime());

    vespalib::asciistream json;
    vespalib::JsonStream stream(json);
    metrics::JsonWriter metricJsonWriter(stream);
    _manager.visit(guard, snapshot, metricJsonWriter, consumer);
    stream.finalize();
    return json.str();
}

vespalib::string
StateReporter::getTotalMetrics(const vespalib::string &consumer)
{
    return _metricsAdapter.getTotalMetrics(consumer);
}

vespalib::HealthProducer::Health
StateReporter::getHealth() const
{
    lib::NodeState cns(*_component.getStateUpdater().getCurrentNodeState());
    bool up = cns.getState().oneOf("u");
    std::string message = up ? "" : "Node state: " + cns.toString(true);
    return { up, message };
}

void
StateReporter::getComponentConfig(Consumer &consumer)
{
    consumer.add(ComponentConfigProducer::Config(_generationFetcher.getComponentName(),
            _generationFetcher.getGeneration()));
}

} // storage