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

jupp0r / prometheus-cpp / 7324270520

25 Dec 2023 08:53PM UTC coverage: 98.248% (+1.7%) from 96.499%
7324270520

Pull #677

github

gjasny
chore(pull): remove pre v1.14 civetweb work-around
Pull Request #677: chore(pull): add more authentication tests

1 of 1 new or added line in 1 file covered. (100.0%)

841 of 856 relevant lines covered (98.25%)

102381.49 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
#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)
28✔
31
    : bytes_transferred_family_(
32
          BuildCounter()
28✔
33
              .Name("exposer_transferred_bytes_total")
56✔
34
              .Help("Transferred bytes to metrics services")
56✔
35
              .Register(registry)),
28✔
36
      bytes_transferred_(bytes_transferred_family_.Add({})),
28✔
37
      num_scrapes_family_(BuildCounter()
28✔
38
                              .Name("exposer_scrapes_total")
56✔
39
                              .Help("Number of times metrics were scraped")
56✔
40
                              .Register(registry)),
28✔
41
      num_scrapes_(num_scrapes_family_.Add({})),
28✔
42
      request_latencies_family_(
43
          BuildSummary()
28✔
44
              .Name("exposer_request_latencies")
56✔
45
              .Help("Latencies of serving scrape requests, in microseconds")
56✔
46
              .Register(registry)),
28✔
47
      request_latencies_(request_latencies_family_.Add(
28✔
48
          {}, Summary::Quantiles{{0.5, 0.05}, {0.9, 0.01}, {0.99, 0.001}})) {}
196✔
49

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

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

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

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

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

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

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

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

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

89
  deflateEnd(&zs);
2✔
90

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

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

99
static std::size_t WriteResponse(struct mg_connection* conn,
16✔
100
                                 const std::string& body) {
101
  mg_printf(conn,
16✔
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");
16✔
107

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

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

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

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

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

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

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

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

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

158
  const TextSerializer serializer;
×
159

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

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

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

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