]>
Commit | Line | Data |
---|---|---|
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 | 33 | GlobalStateHolder<vector<CarbonConfig> > g_carbon; |
61d1b966 | 34 | static time_t s_start=time(0); |
35 | uint64_t uptimeOfProcess(const std::string& str) | |
36 | { | |
37 | return time(0) - s_start; | |
38 | } | |
68ee58b6 | 39 | |
9b73b71c | 40 | void carbonDumpThread() |
68ee58b6 | 41 | try |
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 | } |
260 | catch(std::exception& e) | |
261 | { | |
262 | errlog("Carbon thread died: %s", e.what()); | |
68ee58b6 | 263 | } |
264 | catch(PDNSException& e) | |
265 | { | |
266 | errlog("Carbon thread died, PDNSException: %s", e.reason); | |
68ee58b6 | 267 | } |
268 | catch(...) | |
269 | { | |
270 | errlog("Carbon thread died"); | |
68ee58b6 | 271 | } |