]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdist-carbon.cc
Fix compilation on systems that do not define HOST_NAME_MAX
[thirdparty/pdns.git] / pdns / dnsdist-carbon.cc
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
68ee58b6 22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25#include "iputils.hh"
26#include "dolog.hh"
27#include "sstuff.hh"
fa8fd4d2 28
68ee58b6 29#include "namespaces.hh"
68ee58b6 30#include "dnsdist.hh"
519f5484 31#include "threadname.hh"
68ee58b6 32
d617b22c 33GlobalStateHolder<vector<CarbonConfig> > g_carbon;
61d1b966 34static time_t s_start=time(0);
35uint64_t uptimeOfProcess(const std::string& str)
36{
37 return time(0) - s_start;
38}
68ee58b6 39
9b73b71c 40void carbonDumpThread()
68ee58b6 41try
42{
519f5484 43 setThreadName("dnsdist/carbon");
68ee58b6 44 auto localCarbon = g_carbon.getLocal();
45 for(int numloops=0;;++numloops) {
d617b22c 46 if(localCarbon->empty()) {
68ee58b6 47 sleep(1);
48 continue;
49 }
d617b22c
RG
50 /* this is wrong, we use the interval of the first server
51 for every single one of them */
52 if(numloops) {
53 const unsigned int interval = localCarbon->at(0).interval;
54 sleep(interval);
3565320b 55 }
d617b22c
RG
56
57 for (const auto& conf : *localCarbon) {
58 const auto& server = conf.server;
f7a645ec 59 const std::string& namespace_name = conf.namespace_name;
d617b22c 60 std::string hostname = conf.ourname;
64d38231
RG
61 if (hostname.empty()) {
62 try {
63 hostname = getCarbonHostName();
64 }
65 catch(const std::exception& e) {
66 throw std::runtime_error(std::string("The 'ourname' setting in 'carbonServer()' has not been set and we are unable to determine the system's hostname: ") + e.what());
e7a0f37c 67 }
d617b22c 68 }
f7a645ec 69 const std::string& instance_name = conf.instance_name;
d617b22c 70
3565320b
RG
71 try {
72 Socket s(server.sin4.sin_family, SOCK_STREAM);
73 s.setNonBlocking();
74 s.connect(server); // we do the connect so the attempt happens while we gather stats
75 ostringstream str;
76 time_t now=time(0);
77 for(const auto& e : g_stats.entries) {
813b0ba9 78 str<<namespace_name<<"."<<hostname<<"."<<instance_name<<"."<<e.first<<' ';
3565320b
RG
79 if(const auto& val = boost::get<DNSDistStats::stat_t*>(&e.second))
80 str<<(*val)->load();
af619119
RG
81 else if (const auto& dval = boost::get<double*>(&e.second))
82 str<<**dval;
3565320b
RG
83 else
84 str<<(*boost::get<DNSDistStats::statfunction_t>(&e.second))(e.first);
85 str<<' '<<now<<"\r\n";
86 }
a9c2e4ab
RG
87 auto states = g_dstates.getLocal();
88 for(const auto& state : *states) {
be05aa91 89 string serverName = state->getName().empty() ? (state->remote.toString() + ":" + std::to_string(state->remote.getPort())) : state->getName();
3565320b 90 boost::replace_all(serverName, ".", "_");
6b84eec9 91 const string base = namespace_name + "." + hostname + "." + instance_name + ".servers." + serverName + ".";
af619119 92 str<<base<<"queries" << ' ' << state->queries.load() << " " << now << "\r\n";
7fc95193 93 str<<base<<"responses" << ' ' << state->responses.load() << " " << now << "\r\n";
af619119
RG
94 str<<base<<"drops" << ' ' << state->reuseds.load() << " " << now << "\r\n";
95 str<<base<<"latency" << ' ' << (state->availability != DownstreamState::Availability::Down ? state->latencyUsec/1000.0 : 0) << " " << now << "\r\n";
96 str<<base<<"senderrors" << ' ' << state->sendErrors.load() << " " << now << "\r\n";
97 str<<base<<"outstanding" << ' ' << state->outstanding.load() << " " << now << "\r\n";
2609f6e2
RG
98 str<<base<<"tcpdiedsendingquery" << ' '<< state->tcpDiedSendingQuery.load() << " " << now << "\r\n";
99 str<<base<<"tcpdiedreaddingresponse" << ' '<< state->tcpDiedReadingResponse.load() << " " << now << "\r\n";
100 str<<base<<"tcpgaveup" << ' '<< state->tcpGaveUp.load() << " " << now << "\r\n";
101 str<<base<<"tcpreadimeouts" << ' '<< state->tcpReadTimeouts.load() << " " << now << "\r\n";
102 str<<base<<"tcpwritetimeouts" << ' '<< state->tcpWriteTimeouts.load() << " " << now << "\r\n";
cff9aa03
RG
103 str<<base<<"tcpcurrentconnections" << ' '<< state->tcpCurrentConnections.load() << " " << now << "\r\n";
104 str<<base<<"tcpavgqueriesperconnection" << ' '<< state->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n";
105 str<<base<<"tcpavgconnectionduration" << ' '<< state->tcpAvgConnectionDuration.load() << " " << now << "\r\n";
3565320b 106 }
a8b5b7a7
RG
107
108 std::map<std::string,uint64_t> frontendDuplicates;
3565320b
RG
109 for(const auto& front : g_frontends) {
110 if (front->udpFD == -1 && front->tcpFD == -1)
111 continue;
963bef8d 112
0affb140 113 string frontName = front->local.toString() + ":" + std::to_string(front->local.getPort()) + (front->udpFD >= 0 ? "_udp" : "_tcp");
3565320b 114 boost::replace_all(frontName, ".", "_");
a8b5b7a7 115 auto dupPair = frontendDuplicates.insert({frontName, 1});
131df256 116 if (!dupPair.second) {
a8b5b7a7 117 frontName = frontName + "_" + std::to_string(dupPair.first->second);
131df256 118 ++(dupPair.first->second);
a8b5b7a7
RG
119 }
120
813b0ba9 121 const string base = namespace_name + "." + hostname + "." + instance_name + ".frontends." + frontName + ".";
3565320b 122 str<<base<<"queries" << ' ' << front->queries.load() << " " << now << "\r\n";
7fc95193 123 str<<base<<"responses" << ' ' << front->responses.load() << " " << now << "\r\n";
2609f6e2
RG
124 str<<base<<"tcpdiedreadingquery" << ' '<< front->tcpDiedReadingQuery.load() << " " << now << "\r\n";
125 str<<base<<"tcpdiedsendingresponse" << ' '<< front->tcpDiedSendingResponse.load() << " " << now << "\r\n";
126 str<<base<<"tcpgaveup" << ' '<< front->tcpGaveUp.load() << " " << now << "\r\n";
127 str<<base<<"tcpclientimeouts" << ' '<< front->tcpClientTimeouts.load() << " " << now << "\r\n";
128 str<<base<<"tcpdownstreamtimeouts" << ' '<< front->tcpDownstreamTimeouts.load() << " " << now << "\r\n";
cff9aa03
RG
129 str<<base<<"tcpcurrentconnections" << ' '<< front->tcpCurrentConnections.load() << " " << now << "\r\n";
130 str<<base<<"tcpavgqueriesperconnection" << ' '<< front->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n";
131 str<<base<<"tcpavgconnectionduration" << ' '<< front->tcpAvgConnectionDuration.load() << " " << now << "\r\n";
bb3954f0
RG
132 str<<base<<"tls10-queries" << ' ' << front->tls10queries.load() << " " << now << "\r\n";
133 str<<base<<"tls11-queries" << ' ' << front->tls11queries.load() << " " << now << "\r\n";
134 str<<base<<"tls12-queries" << ' ' << front->tls12queries.load() << " " << now << "\r\n";
135 str<<base<<"tls13-queries" << ' ' << front->tls13queries.load() << " " << now << "\r\n";
136 str<<base<<"tls-unknown-queries" << ' ' << front->tlsUnknownqueries.load() << " " << now << "\r\n";
b608e6c6
RG
137 str<<base<<"tlsnewsessions" << ' ' << front->tlsNewSessions.load() << " " << now << "\r\n";
138 str<<base<<"tlsresumptions" << ' ' << front->tlsResumptions.load() << " " << now << "\r\n";
139 str<<base<<"tlsunknownticketkeys" << ' ' << front->tlsUnknownTicketKey.load() << " " << now << "\r\n";
140 str<<base<<"tlsinactiveticketkeys" << ' ' << front->tlsInactiveTicketKey.load() << " " << now << "\r\n";
f34fdcc5
RG
141 const TLSErrorCounters* errorCounters = nullptr;
142 if (front->tlsFrontend != nullptr) {
143 errorCounters = &front->tlsFrontend->d_tlsCounters;
144 }
145 else if (front->dohFrontend != nullptr) {
146 errorCounters = &front->dohFrontend->d_tlsCounters;
147 }
148 if (errorCounters != nullptr) {
149 str<<base<<"tlsdhkeytoosmall" << ' ' << errorCounters->d_dhKeyTooSmall << " " << now << "\r\n";
150 str<<base<<"tlsinappropriatefallback" << ' ' << errorCounters->d_inappropriateFallBack << " " << now << "\r\n";
151 str<<base<<"tlsnosharedcipher" << ' ' << errorCounters->d_noSharedCipher << " " << now << "\r\n";
152 str<<base<<"tlsunknownciphertype" << ' ' << errorCounters->d_unknownCipherType << " " << now << "\r\n";
153 str<<base<<"tlsunknownkeyexchangetype" << ' ' << errorCounters->d_unknownKeyExchangeType << " " << now << "\r\n";
154 str<<base<<"tlsunknownprotocol" << ' ' << errorCounters->d_unknownProtocol << " " << now << "\r\n";
155 str<<base<<"tlsunsupportedec" << ' ' << errorCounters->d_unsupportedEC << " " << now << "\r\n";
156 str<<base<<"tlsunsupportedprotocol" << ' ' << errorCounters->d_unsupportedProtocol << " " << now << "\r\n";
157 }
3565320b 158 }
a8b5b7a7 159
a9c2e4ab
RG
160 auto localPools = g_pools.getLocal();
161 for (const auto& entry : *localPools) {
9e9be156
RG
162 string poolName = entry.first;
163 boost::replace_all(poolName, ".", "_");
164 if (poolName.empty()) {
165 poolName = "_default_";
166 }
813b0ba9 167 const string base = namespace_name + "." + hostname + "." + instance_name + ".pools." + poolName + ".";
9e9be156 168 const std::shared_ptr<ServerPool> pool = entry.second;
a1b1a29d
RG
169 str<<base<<"servers" << " " << pool->countServers(false) << " " << now << "\r\n";
170 str<<base<<"servers-up" << " " << pool->countServers(true) << " " << now << "\r\n";
9e9be156
RG
171 if (pool->packetCache != nullptr) {
172 const auto& cache = pool->packetCache;
173 str<<base<<"cache-size" << " " << cache->getMaxEntries() << " " << now << "\r\n";
174 str<<base<<"cache-entries" << " " << cache->getEntriesCount() << " " << now << "\r\n";
175 str<<base<<"cache-hits" << " " << cache->getHits() << " " << now << "\r\n";
176 str<<base<<"cache-misses" << " " << cache->getMisses() << " " << now << "\r\n";
177 str<<base<<"cache-deferred-inserts" << " " << cache->getDeferredInserts() << " " << now << "\r\n";
178 str<<base<<"cache-deferred-lookups" << " " << cache->getDeferredLookups() << " " << now << "\r\n";
179 str<<base<<"cache-lookup-collisions" << " " << cache->getLookupCollisions() << " " << now << "\r\n";
180 str<<base<<"cache-insert-collisions" << " " << cache->getInsertCollisions() << " " << now << "\r\n";
cc8cefe1 181 str<<base<<"cache-ttl-too-shorts" << " " << cache->getTTLTooShorts() << " " << now << "\r\n";
9e9be156
RG
182 }
183 }
786e4d8c 184
fbf14b03
RG
185#ifdef HAVE_DNS_OVER_HTTPS
186 {
a8b5b7a7 187 std::map<std::string,uint64_t> dohFrontendDuplicates;
fbf14b03
RG
188 const string base = "dnsdist." + hostname + ".main.doh.";
189 for(const auto& doh : g_dohlocals) {
190 string name = doh->d_local.toStringWithPort();
191 boost::replace_all(name, ".", "_");
192 boost::replace_all(name, ":", "_");
193 boost::replace_all(name, "[", "_");
194 boost::replace_all(name, "]", "_");
195
a8b5b7a7 196 auto dupPair = dohFrontendDuplicates.insert({name, 1});
131df256 197 if (!dupPair.second) {
a8b5b7a7 198 name = name + "_" + std::to_string(dupPair.first->second);
131df256 199 ++(dupPair.first->second);
a8b5b7a7
RG
200 }
201
fbf14b03
RG
202 vector<pair<const char*, const std::atomic<uint64_t>&>> v{
203 {"http-connects", doh->d_httpconnects},
5bbcbea0
RG
204 {"http1-queries", doh->d_http1Stats.d_nbQueries},
205 {"http2-queries", doh->d_http2Stats.d_nbQueries},
206 {"http1-200-responses", doh->d_http1Stats.d_nb200Responses},
207 {"http2-200-responses", doh->d_http2Stats.d_nb200Responses},
208 {"http1-400-responses", doh->d_http1Stats.d_nb400Responses},
209 {"http2-400-responses", doh->d_http2Stats.d_nb400Responses},
210 {"http1-403-responses", doh->d_http1Stats.d_nb403Responses},
211 {"http2-403-responses", doh->d_http2Stats.d_nb403Responses},
212 {"http1-500-responses", doh->d_http1Stats.d_nb500Responses},
213 {"http2-500-responses", doh->d_http2Stats.d_nb500Responses},
214 {"http1-502-responses", doh->d_http1Stats.d_nb502Responses},
215 {"http2-502-responses", doh->d_http2Stats.d_nb502Responses},
216 {"http1-other-responses", doh->d_http1Stats.d_nbOtherResponses},
217 {"http2-other-responses", doh->d_http2Stats.d_nbOtherResponses},
fbf14b03
RG
218 {"get-queries", doh->d_getqueries},
219 {"post-queries", doh->d_postqueries},
220 {"bad-requests", doh->d_badrequests},
221 {"error-responses", doh->d_errorresponses},
1ddac024 222 {"redirect-responses", doh->d_redirectresponses},
fbf14b03
RG
223 {"valid-responses", doh->d_validresponses}
224 };
225
226 for(const auto& item : v) {
227 str<<base<<name<<"."<<item.first << " " << item.second << " " << now <<"\r\n";
228 }
229 }
230 }
231#endif /* HAVE_DNS_OVER_HTTPS */
232
786e4d8c
RS
233 {
234 WriteLock wl(&g_qcount.queryLock);
235 std::string qname;
236 for(auto &record: g_qcount.records) {
237 qname = record.first;
238 boost::replace_all(qname, ".", "_");
239 str<<"dnsdist.querycount." << qname << ".queries " << record.second << " " << now << "\r\n";
240 }
241 g_qcount.records.clear();
242 }
243
3565320b 244 const string msg = str.str();
a1a787dc 245
3565320b
RG
246 int ret = waitForRWData(s.getHandle(), false, 1 , 0);
247 if(ret <= 0 ) {
04360367 248 vinfolog("Unable to write data to carbon server on %s: %s", server.toStringWithPort(), (ret<0 ? stringerror() : "Timeout"));
3565320b
RG
249 continue;
250 }
251 s.setBlocking();
a683e8bd 252 writen2(s.getHandle(), msg.c_str(), msg.size());
3565320b
RG
253 }
254 catch(std::exception& e) {
255 warnlog("Problem sending carbon data: %s", e.what());
68ee58b6 256 }
68ee58b6 257 }
258 }
68ee58b6 259}
260catch(std::exception& e)
261{
262 errlog("Carbon thread died: %s", e.what());
68ee58b6 263}
264catch(PDNSException& e)
265{
266 errlog("Carbon thread died, PDNSException: %s", e.reason);
68ee58b6 267}
268catch(...)
269{
270 errlog("Carbon thread died");
68ee58b6 271}