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

jupp0r / prometheus-cpp / 14010370149

22 Mar 2025 04:28PM UTC coverage: 98.534%. Remained the same
14010370149

push

github

gjasny
ci: fix coverage generation

874 of 887 relevant lines covered (98.53%)

49857.53 hits per line

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

97.98
/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
#if CIVETWEB_VERSION_MAJOR < 1 || \
22
    (CIVETWEB_VERSION_MAJOR == 1 && CIVETWEB_VERSION_MINOR < 14)
23
// https://github.com/civetweb/civetweb/issues/954
24
#error "Civetweb version 1.14 or higher required"
25
#endif
26

27
namespace prometheus {
28
namespace detail {
29

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

50
#ifdef HAVE_ZLIB
51
static bool IsEncodingAccepted(struct mg_connection* conn,
8✔
52
                               const char* encoding) {
53
  auto accept_encoding = mg_get_header(conn, "Accept-Encoding");
8✔
54
  if (!accept_encoding) {
8✔
55
    return false;
7✔
56
  }
57
  return std::strstr(accept_encoding, encoding) != nullptr;
1✔
58
}
59

60
static std::vector<Byte> GZipCompress(const std::string& input) {
1✔
61
  auto zs = z_stream{};
1✔
62
  auto windowSize = 16 + MAX_WBITS;
1✔
63
  auto memoryLevel = 9;
1✔
64

65
  if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, windowSize,
1✔
66
                   memoryLevel, Z_DEFAULT_STRATEGY) != Z_OK) {
1✔
67
    return {};
×
68
  }
69

70
  zs.next_in = (Bytef*)input.data();
1✔
71
  zs.avail_in = input.size();
1✔
72

73
  int ret;
74
  std::vector<Byte> output;
1✔
75
  output.reserve(input.size() / 2u);
1✔
76

77
  do {
78
    static const auto outputBytesPerRound = std::size_t{32768};
79

80
    zs.avail_out = outputBytesPerRound;
1✔
81
    output.resize(zs.total_out + zs.avail_out);
1✔
82
    zs.next_out = reinterpret_cast<Bytef*>(output.data() + zs.total_out);
1✔
83

84
    ret = deflate(&zs, Z_FINISH);
1✔
85

86
    output.resize(zs.total_out);
1✔
87
  } while (ret == Z_OK);
1✔
88

89
  deflateEnd(&zs);
1✔
90

91
  if (ret != Z_STREAM_END) {
1✔
92
    return {};
×
93
  }
94

95
  return output;
1✔
96
}
1✔
97
#endif
98

99
static std::size_t WriteResponse(struct mg_connection* conn,
8✔
100
                                 const std::string& body) {
101
  mg_printf(conn,
8✔
102
            "HTTP/1.1 200 OK\r\n"
103
            "Content-Type: text/plain; charset=utf-8\r\n");
104

105
#ifdef HAVE_ZLIB
106
  auto acceptsGzip = IsEncodingAccepted(conn, "gzip");
8✔
107

108
  if (acceptsGzip) {
8✔
109
    auto compressed = GZipCompress(body);
1✔
110
    if (!compressed.empty()) {
1✔
111
      mg_printf(conn,
1✔
112
                "Content-Encoding: gzip\r\n"
113
                "Content-Length: %lu\r\n\r\n",
114
                static_cast<unsigned long>(compressed.size()));
1✔
115
      mg_write(conn, compressed.data(), compressed.size());
1✔
116
      return compressed.size();
1✔
117
    }
118
  }
1✔
119
#endif
120

121
  mg_printf(conn, "Content-Length: %lu\r\n\r\n",
7✔
122
            static_cast<unsigned long>(body.size()));
7✔
123
  mg_write(conn, body.data(), body.size());
7✔
124
  return body.size();
7✔
125
}
126

127
void MetricsHandler::RegisterCollectable(
27✔
128
    const std::weak_ptr<Collectable>& collectable) {
129
  std::lock_guard<std::mutex> lock{collectables_mutex_};
27✔
130
  CleanupStalePointers(collectables_);
27✔
131
  collectables_.push_back(collectable);
27✔
132
}
27✔
133

134
void MetricsHandler::RemoveCollectable(
1✔
135
    const std::weak_ptr<Collectable>& collectable) {
136
  std::lock_guard<std::mutex> lock{collectables_mutex_};
1✔
137

138
  auto locked = collectable.lock();
1✔
139
  auto same_pointer = [&locked](const std::weak_ptr<Collectable>& candidate) {
2✔
140
    return locked == candidate.lock();
2✔
141
  };
1✔
142

143
  collectables_.erase(std::remove_if(std::begin(collectables_),
2✔
144
                                     std::end(collectables_), same_pointer),
1✔
145
                      std::end(collectables_));
2✔
146
}
1✔
147

148
bool MetricsHandler::handleGet(CivetServer*, struct mg_connection* conn) {
8✔
149
  auto start_time_of_request = std::chrono::steady_clock::now();
8✔
150

151
  std::vector<MetricFamily> metrics;
8✔
152

153
  {
154
    std::lock_guard<std::mutex> lock{collectables_mutex_};
8✔
155
    metrics = CollectMetrics(collectables_);
8✔
156
  }
8✔
157

158
  const TextSerializer serializer;
8✔
159

160
  auto bodySize = WriteResponse(conn, serializer.Serialize(metrics));
8✔
161

162
  auto stop_time_of_request = std::chrono::steady_clock::now();
8✔
163
  auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
8✔
164
      stop_time_of_request - start_time_of_request);
8✔
165
  request_latencies_.Observe(duration.count());
8✔
166

167
  bytes_transferred_.Increment(bodySize);
8✔
168
  num_scrapes_.Increment();
8✔
169
  return true;
8✔
170
}
8✔
171

172
void MetricsHandler::CleanupStalePointers(
27✔
173
    std::vector<std::weak_ptr<Collectable>>& collectables) {
174
  collectables.erase(
27✔
175
      std::remove_if(std::begin(collectables), std::end(collectables),
27✔
176
                     [](const std::weak_ptr<Collectable>& candidate) {
15✔
177
                       return candidate.expired();
15✔
178
                     }),
179
      std::end(collectables));
27✔
180
}
27✔
181
}  // namespace detail
182
}  // 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