• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jupp0r / prometheus-cpp / 4192383612

pending completion
4192383612

Pull #634

github

GitHub
Merge 039bc354a into 1833c1848
Pull Request #634: Update deps

773 of 802 relevant lines covered (96.38%)

109256.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.55
/pull/src/handler.cc
1
#include "handler.h"
2

3
#include <algorithm>
4
#include <chrono>
5
#include <cstring>
6
#include <iterator>
7
#include <string>
8

9
#ifdef HAVE_ZLIB
10
#include <zconf.h>
11
#include <zlib.h>
12
#endif
13

14
#include "civetweb.h"
15
#include "metrics_collector.h"
16
#include "prometheus/counter.h"
17
#include "prometheus/metric_family.h"
18
#include "prometheus/summary.h"
19
#include "prometheus/text_serializer.h"
20

21
namespace prometheus {
22
namespace detail {
23

24
MetricsHandler::MetricsHandler(Registry& registry)
16✔
25
    : bytes_transferred_family_(
26
          BuildCounter()
16✔
27
              .Name("exposer_transferred_bytes_total")
32✔
28
              .Help("Transferred bytes to metrics services")
32✔
29
              .Register(registry)),
16✔
30
      bytes_transferred_(bytes_transferred_family_.Add({})),
16✔
31
      num_scrapes_family_(BuildCounter()
16✔
32
                              .Name("exposer_scrapes_total")
32✔
33
                              .Help("Number of times metrics were scraped")
32✔
34
                              .Register(registry)),
16✔
35
      num_scrapes_(num_scrapes_family_.Add({})),
16✔
36
      request_latencies_family_(
37
          BuildSummary()
16✔
38
              .Name("exposer_request_latencies")
32✔
39
              .Help("Latencies of serving scrape requests, in microseconds")
32✔
40
              .Register(registry)),
16✔
41
      request_latencies_(request_latencies_family_.Add(
16✔
42
          {}, Summary::Quantiles{{0.5, 0.05}, {0.9, 0.01}, {0.99, 0.001}})) {}
112✔
43

44
#ifdef HAVE_ZLIB
45
static bool IsEncodingAccepted(struct mg_connection* conn,
16✔
46
                               const char* encoding) {
47
  auto accept_encoding = mg_get_header(conn, "Accept-Encoding");
16✔
48
  if (!accept_encoding) {
16✔
49
    return false;
14✔
50
  }
51
  return std::strstr(accept_encoding, encoding) != nullptr;
2✔
52
}
53

54
static std::vector<Byte> GZipCompress(const std::string& input) {
2✔
55
  auto zs = z_stream{};
2✔
56
  auto windowSize = 16 + MAX_WBITS;
2✔
57
  auto memoryLevel = 9;
2✔
58

59
  if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, windowSize,
2✔
60
                   memoryLevel, Z_DEFAULT_STRATEGY) != Z_OK) {
2✔
61
    return {};
×
62
  }
63

64
  zs.next_in = (Bytef*)input.data();
2✔
65
  zs.avail_in = input.size();
2✔
66

67
  int ret;
68
  std::vector<Byte> output;
4✔
69
  output.reserve(input.size() / 2u);
2✔
70

71
  do {
×
72
    static const auto outputBytesPerRound = std::size_t{32768};
73

74
    zs.avail_out = outputBytesPerRound;
2✔
75
    output.resize(zs.total_out + zs.avail_out);
2✔
76
    zs.next_out = reinterpret_cast<Bytef*>(output.data() + zs.total_out);
2✔
77

78
    ret = deflate(&zs, Z_FINISH);
2✔
79

80
    output.resize(zs.total_out);
2✔
81
  } while (ret == Z_OK);
2✔
82

83
  deflateEnd(&zs);
2✔
84

85
  if (ret != Z_STREAM_END) {
2✔
86
    return {};
×
87
  }
88

89
  return output;
2✔
90
}
91
#endif
92

93
static std::size_t WriteResponse(struct mg_connection* conn,
16✔
94
                                 const std::string& body) {
95
  mg_printf(conn,
16✔
96
            "HTTP/1.1 200 OK\r\n"
97
            "Content-Type: text/plain; charset=utf-8\r\n");
98

99
#ifdef HAVE_ZLIB
100
  auto acceptsGzip = IsEncodingAccepted(conn, "gzip");
16✔
101

102
  if (acceptsGzip) {
16✔
103
    auto compressed = GZipCompress(body);
2✔
104
    if (!compressed.empty()) {
2✔
105
      mg_printf(conn,
2✔
106
                "Content-Encoding: gzip\r\n"
107
                "Content-Length: %lu\r\n\r\n",
108
                static_cast<unsigned long>(compressed.size()));
2✔
109
      mg_write(conn, compressed.data(), compressed.size());
2✔
110
      return compressed.size();
2✔
111
    }
112
  }
113
#endif
114

115
  mg_printf(conn, "Content-Length: %lu\r\n\r\n",
14✔
116
            static_cast<unsigned long>(body.size()));
14✔
117
  mg_write(conn, body.data(), body.size());
14✔
118
  return body.size();
14✔
119
}
120

121
void MetricsHandler::RegisterCollectable(
34✔
122
    const std::weak_ptr<Collectable>& collectable) {
123
  std::lock_guard<std::mutex> lock{collectables_mutex_};
68✔
124
  CleanupStalePointers(collectables_);
34✔
125
  collectables_.push_back(collectable);
34✔
126
}
34✔
127

128
void MetricsHandler::RemoveCollectable(
2✔
129
    const std::weak_ptr<Collectable>& collectable) {
130
  std::lock_guard<std::mutex> lock{collectables_mutex_};
4✔
131

132
  auto locked = collectable.lock();
2✔
133
  auto same_pointer = [&locked](const std::weak_ptr<Collectable>& candidate) {
8✔
134
    return locked == candidate.lock();
4✔
135
  };
2✔
136

137
  collectables_.erase(std::remove_if(std::begin(collectables_),
×
138
                                     std::end(collectables_), same_pointer),
2✔
139
                      std::end(collectables_));
4✔
140
}
2✔
141

142
bool MetricsHandler::handleGet(CivetServer*, struct mg_connection* conn) {
16✔
143
  auto start_time_of_request = std::chrono::steady_clock::now();
16✔
144

145
  std::vector<MetricFamily> metrics;
32✔
146

147
  {
148
    std::lock_guard<std::mutex> lock{collectables_mutex_};
16✔
149
    metrics = CollectMetrics(collectables_);
16✔
150
  }
151

152
  const TextSerializer serializer;
×
153

154
  auto bodySize = WriteResponse(conn, serializer.Serialize(metrics));
16✔
155

156
  auto stop_time_of_request = std::chrono::steady_clock::now();
16✔
157
  auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
158
      stop_time_of_request - start_time_of_request);
16✔
159
  request_latencies_.Observe(duration.count());
16✔
160

161
  bytes_transferred_.Increment(bodySize);
16✔
162
  num_scrapes_.Increment();
16✔
163
  return true;
32✔
164
}
165

166
void MetricsHandler::CleanupStalePointers(
34✔
167
    std::vector<std::weak_ptr<Collectable>>& collectables) {
168
  collectables.erase(
169
      std::remove_if(std::begin(collectables), std::end(collectables),
×
170
                     [](const std::weak_ptr<Collectable>& candidate) {
20✔
171
                       return candidate.expired();
20✔
172
                     }),
34✔
173
      std::end(collectables));
68✔
174
}
34✔
175
}  // namespace detail
176
}  // namespace prometheus
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc