]>
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 RG |
60 | std::string hostname = conf.ourname; |
61 | if(hostname.empty()) { | |
62 | char tmp[80]; | |
63 | memset(tmp, 0, sizeof(tmp)); | |
64 | gethostname(tmp, sizeof(tmp)); | |
65 | char *p = strchr(tmp, '.'); | |
66 | if(p) *p=0; | |
67 | hostname=tmp; | |
68 | boost::replace_all(hostname, ".", "_"); | |
69 | } | |
f7a645ec | 70 | const std::string& instance_name = conf.instance_name; |
d617b22c | 71 | |
3565320b RG |
72 | try { |
73 | Socket s(server.sin4.sin_family, SOCK_STREAM); | |
74 | s.setNonBlocking(); | |
75 | s.connect(server); // we do the connect so the attempt happens while we gather stats | |
76 | ostringstream str; | |
77 | time_t now=time(0); | |
78 | for(const auto& e : g_stats.entries) { | |
813b0ba9 | 79 | str<<namespace_name<<"."<<hostname<<"."<<instance_name<<"."<<e.first<<' '; |
3565320b RG |
80 | if(const auto& val = boost::get<DNSDistStats::stat_t*>(&e.second)) |
81 | str<<(*val)->load(); | |
af619119 RG |
82 | else if (const auto& dval = boost::get<double*>(&e.second)) |
83 | str<<**dval; | |
3565320b RG |
84 | else |
85 | str<<(*boost::get<DNSDistStats::statfunction_t>(&e.second))(e.first); | |
86 | str<<' '<<now<<"\r\n"; | |
87 | } | |
a9c2e4ab RG |
88 | auto states = g_dstates.getLocal(); |
89 | for(const auto& state : *states) { | |
be05aa91 | 90 | string serverName = state->getName().empty() ? (state->remote.toString() + ":" + std::to_string(state->remote.getPort())) : state->getName(); |
3565320b | 91 | boost::replace_all(serverName, ".", "_"); |
6b84eec9 | 92 | const string base = namespace_name + "." + hostname + "." + instance_name + ".servers." + serverName + "."; |
af619119 | 93 | str<<base<<"queries" << ' ' << state->queries.load() << " " << now << "\r\n"; |
7fc95193 | 94 | str<<base<<"responses" << ' ' << state->responses.load() << " " << now << "\r\n"; |
af619119 RG |
95 | str<<base<<"drops" << ' ' << state->reuseds.load() << " " << now << "\r\n"; |
96 | str<<base<<"latency" << ' ' << (state->availability != DownstreamState::Availability::Down ? state->latencyUsec/1000.0 : 0) << " " << now << "\r\n"; | |
97 | str<<base<<"senderrors" << ' ' << state->sendErrors.load() << " " << now << "\r\n"; | |
98 | str<<base<<"outstanding" << ' ' << state->outstanding.load() << " " << now << "\r\n"; | |
2609f6e2 RG |
99 | str<<base<<"tcpdiedsendingquery" << ' '<< state->tcpDiedSendingQuery.load() << " " << now << "\r\n"; |
100 | str<<base<<"tcpdiedreaddingresponse" << ' '<< state->tcpDiedReadingResponse.load() << " " << now << "\r\n"; | |
101 | str<<base<<"tcpgaveup" << ' '<< state->tcpGaveUp.load() << " " << now << "\r\n"; | |
102 | str<<base<<"tcpreadimeouts" << ' '<< state->tcpReadTimeouts.load() << " " << now << "\r\n"; | |
103 | str<<base<<"tcpwritetimeouts" << ' '<< state->tcpWriteTimeouts.load() << " " << now << "\r\n"; | |
cff9aa03 RG |
104 | str<<base<<"tcpcurrentconnections" << ' '<< state->tcpCurrentConnections.load() << " " << now << "\r\n"; |
105 | str<<base<<"tcpavgqueriesperconnection" << ' '<< state->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n"; | |
106 | str<<base<<"tcpavgconnectionduration" << ' '<< state->tcpAvgConnectionDuration.load() << " " << now << "\r\n"; | |
3565320b | 107 | } |
a8b5b7a7 RG |
108 | |
109 | std::map<std::string,uint64_t> frontendDuplicates; | |
3565320b RG |
110 | for(const auto& front : g_frontends) { |
111 | if (front->udpFD == -1 && front->tcpFD == -1) | |
112 | continue; | |
963bef8d | 113 | |
0affb140 | 114 | string frontName = front->local.toString() + ":" + std::to_string(front->local.getPort()) + (front->udpFD >= 0 ? "_udp" : "_tcp"); |
3565320b | 115 | boost::replace_all(frontName, ".", "_"); |
a8b5b7a7 | 116 | auto dupPair = frontendDuplicates.insert({frontName, 1}); |
131df256 | 117 | if (!dupPair.second) { |
a8b5b7a7 | 118 | frontName = frontName + "_" + std::to_string(dupPair.first->second); |
131df256 | 119 | ++(dupPair.first->second); |
a8b5b7a7 RG |
120 | } |
121 | ||
813b0ba9 | 122 | const string base = namespace_name + "." + hostname + "." + instance_name + ".frontends." + frontName + "."; |
3565320b | 123 | str<<base<<"queries" << ' ' << front->queries.load() << " " << now << "\r\n"; |
7fc95193 | 124 | str<<base<<"responses" << ' ' << front->responses.load() << " " << now << "\r\n"; |
2609f6e2 RG |
125 | str<<base<<"tcpdiedreadingquery" << ' '<< front->tcpDiedReadingQuery.load() << " " << now << "\r\n"; |
126 | str<<base<<"tcpdiedsendingresponse" << ' '<< front->tcpDiedSendingResponse.load() << " " << now << "\r\n"; | |
127 | str<<base<<"tcpgaveup" << ' '<< front->tcpGaveUp.load() << " " << now << "\r\n"; | |
128 | str<<base<<"tcpclientimeouts" << ' '<< front->tcpClientTimeouts.load() << " " << now << "\r\n"; | |
129 | str<<base<<"tcpdownstreamtimeouts" << ' '<< front->tcpDownstreamTimeouts.load() << " " << now << "\r\n"; | |
cff9aa03 RG |
130 | str<<base<<"tcpcurrentconnections" << ' '<< front->tcpCurrentConnections.load() << " " << now << "\r\n"; |
131 | str<<base<<"tcpavgqueriesperconnection" << ' '<< front->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n"; | |
132 | str<<base<<"tcpavgconnectionduration" << ' '<< front->tcpAvgConnectionDuration.load() << " " << now << "\r\n"; | |
bb3954f0 RG |
133 | str<<base<<"tls10-queries" << ' ' << front->tls10queries.load() << " " << now << "\r\n"; |
134 | str<<base<<"tls11-queries" << ' ' << front->tls11queries.load() << " " << now << "\r\n"; | |
135 | str<<base<<"tls12-queries" << ' ' << front->tls12queries.load() << " " << now << "\r\n"; | |
136 | str<<base<<"tls13-queries" << ' ' << front->tls13queries.load() << " " << now << "\r\n"; | |
137 | str<<base<<"tls-unknown-queries" << ' ' << front->tlsUnknownqueries.load() << " " << now << "\r\n"; | |
b608e6c6 RG |
138 | str<<base<<"tlsnewsessions" << ' ' << front->tlsNewSessions.load() << " " << now << "\r\n"; |
139 | str<<base<<"tlsresumptions" << ' ' << front->tlsResumptions.load() << " " << now << "\r\n"; | |
140 | str<<base<<"tlsunknownticketkeys" << ' ' << front->tlsUnknownTicketKey.load() << " " << now << "\r\n"; | |
141 | str<<base<<"tlsinactiveticketkeys" << ' ' << front->tlsInactiveTicketKey.load() << " " << now << "\r\n"; | |
f34fdcc5 RG |
142 | const TLSErrorCounters* errorCounters = nullptr; |
143 | if (front->tlsFrontend != nullptr) { | |
144 | errorCounters = &front->tlsFrontend->d_tlsCounters; | |
145 | } | |
146 | else if (front->dohFrontend != nullptr) { | |
147 | errorCounters = &front->dohFrontend->d_tlsCounters; | |
148 | } | |
149 | if (errorCounters != nullptr) { | |
150 | str<<base<<"tlsdhkeytoosmall" << ' ' << errorCounters->d_dhKeyTooSmall << " " << now << "\r\n"; | |
151 | str<<base<<"tlsinappropriatefallback" << ' ' << errorCounters->d_inappropriateFallBack << " " << now << "\r\n"; | |
152 | str<<base<<"tlsnosharedcipher" << ' ' << errorCounters->d_noSharedCipher << " " << now << "\r\n"; | |
153 | str<<base<<"tlsunknownciphertype" << ' ' << errorCounters->d_unknownCipherType << " " << now << "\r\n"; | |
154 | str<<base<<"tlsunknownkeyexchangetype" << ' ' << errorCounters->d_unknownKeyExchangeType << " " << now << "\r\n"; | |
155 | str<<base<<"tlsunknownprotocol" << ' ' << errorCounters->d_unknownProtocol << " " << now << "\r\n"; | |
156 | str<<base<<"tlsunsupportedec" << ' ' << errorCounters->d_unsupportedEC << " " << now << "\r\n"; | |
157 | str<<base<<"tlsunsupportedprotocol" << ' ' << errorCounters->d_unsupportedProtocol << " " << now << "\r\n"; | |
158 | } | |
3565320b | 159 | } |
a8b5b7a7 | 160 | |
a9c2e4ab RG |
161 | auto localPools = g_pools.getLocal(); |
162 | for (const auto& entry : *localPools) { | |
9e9be156 RG |
163 | string poolName = entry.first; |
164 | boost::replace_all(poolName, ".", "_"); | |
165 | if (poolName.empty()) { | |
166 | poolName = "_default_"; | |
167 | } | |
813b0ba9 | 168 | const string base = namespace_name + "." + hostname + "." + instance_name + ".pools." + poolName + "."; |
9e9be156 | 169 | const std::shared_ptr<ServerPool> pool = entry.second; |
a1b1a29d RG |
170 | str<<base<<"servers" << " " << pool->countServers(false) << " " << now << "\r\n"; |
171 | str<<base<<"servers-up" << " " << pool->countServers(true) << " " << now << "\r\n"; | |
9e9be156 RG |
172 | if (pool->packetCache != nullptr) { |
173 | const auto& cache = pool->packetCache; | |
174 | str<<base<<"cache-size" << " " << cache->getMaxEntries() << " " << now << "\r\n"; | |
175 | str<<base<<"cache-entries" << " " << cache->getEntriesCount() << " " << now << "\r\n"; | |
176 | str<<base<<"cache-hits" << " " << cache->getHits() << " " << now << "\r\n"; | |
177 | str<<base<<"cache-misses" << " " << cache->getMisses() << " " << now << "\r\n"; | |
178 | str<<base<<"cache-deferred-inserts" << " " << cache->getDeferredInserts() << " " << now << "\r\n"; | |
179 | str<<base<<"cache-deferred-lookups" << " " << cache->getDeferredLookups() << " " << now << "\r\n"; | |
180 | str<<base<<"cache-lookup-collisions" << " " << cache->getLookupCollisions() << " " << now << "\r\n"; | |
181 | str<<base<<"cache-insert-collisions" << " " << cache->getInsertCollisions() << " " << now << "\r\n"; | |
cc8cefe1 | 182 | str<<base<<"cache-ttl-too-shorts" << " " << cache->getTTLTooShorts() << " " << now << "\r\n"; |
9e9be156 RG |
183 | } |
184 | } | |
786e4d8c | 185 | |
fbf14b03 RG |
186 | #ifdef HAVE_DNS_OVER_HTTPS |
187 | { | |
a8b5b7a7 | 188 | std::map<std::string,uint64_t> dohFrontendDuplicates; |
fbf14b03 RG |
189 | const string base = "dnsdist." + hostname + ".main.doh."; |
190 | for(const auto& doh : g_dohlocals) { | |
191 | string name = doh->d_local.toStringWithPort(); | |
192 | boost::replace_all(name, ".", "_"); | |
193 | boost::replace_all(name, ":", "_"); | |
194 | boost::replace_all(name, "[", "_"); | |
195 | boost::replace_all(name, "]", "_"); | |
196 | ||
a8b5b7a7 | 197 | auto dupPair = dohFrontendDuplicates.insert({name, 1}); |
131df256 | 198 | if (!dupPair.second) { |
a8b5b7a7 | 199 | name = name + "_" + std::to_string(dupPair.first->second); |
131df256 | 200 | ++(dupPair.first->second); |
a8b5b7a7 RG |
201 | } |
202 | ||
fbf14b03 RG |
203 | vector<pair<const char*, const std::atomic<uint64_t>&>> v{ |
204 | {"http-connects", doh->d_httpconnects}, | |
5bbcbea0 RG |
205 | {"http1-queries", doh->d_http1Stats.d_nbQueries}, |
206 | {"http2-queries", doh->d_http2Stats.d_nbQueries}, | |
207 | {"http1-200-responses", doh->d_http1Stats.d_nb200Responses}, | |
208 | {"http2-200-responses", doh->d_http2Stats.d_nb200Responses}, | |
209 | {"http1-400-responses", doh->d_http1Stats.d_nb400Responses}, | |
210 | {"http2-400-responses", doh->d_http2Stats.d_nb400Responses}, | |
211 | {"http1-403-responses", doh->d_http1Stats.d_nb403Responses}, | |
212 | {"http2-403-responses", doh->d_http2Stats.d_nb403Responses}, | |
213 | {"http1-500-responses", doh->d_http1Stats.d_nb500Responses}, | |
214 | {"http2-500-responses", doh->d_http2Stats.d_nb500Responses}, | |
215 | {"http1-502-responses", doh->d_http1Stats.d_nb502Responses}, | |
216 | {"http2-502-responses", doh->d_http2Stats.d_nb502Responses}, | |
217 | {"http1-other-responses", doh->d_http1Stats.d_nbOtherResponses}, | |
218 | {"http2-other-responses", doh->d_http2Stats.d_nbOtherResponses}, | |
fbf14b03 RG |
219 | {"get-queries", doh->d_getqueries}, |
220 | {"post-queries", doh->d_postqueries}, | |
221 | {"bad-requests", doh->d_badrequests}, | |
222 | {"error-responses", doh->d_errorresponses}, | |
1ddac024 | 223 | {"redirect-responses", doh->d_redirectresponses}, |
fbf14b03 RG |
224 | {"valid-responses", doh->d_validresponses} |
225 | }; | |
226 | ||
227 | for(const auto& item : v) { | |
228 | str<<base<<name<<"."<<item.first << " " << item.second << " " << now <<"\r\n"; | |
229 | } | |
230 | } | |
231 | } | |
232 | #endif /* HAVE_DNS_OVER_HTTPS */ | |
233 | ||
786e4d8c RS |
234 | { |
235 | WriteLock wl(&g_qcount.queryLock); | |
236 | std::string qname; | |
237 | for(auto &record: g_qcount.records) { | |
238 | qname = record.first; | |
239 | boost::replace_all(qname, ".", "_"); | |
240 | str<<"dnsdist.querycount." << qname << ".queries " << record.second << " " << now << "\r\n"; | |
241 | } | |
242 | g_qcount.records.clear(); | |
243 | } | |
244 | ||
3565320b | 245 | const string msg = str.str(); |
a1a787dc | 246 | |
3565320b RG |
247 | int ret = waitForRWData(s.getHandle(), false, 1 , 0); |
248 | if(ret <= 0 ) { | |
04360367 | 249 | vinfolog("Unable to write data to carbon server on %s: %s", server.toStringWithPort(), (ret<0 ? stringerror() : "Timeout")); |
3565320b RG |
250 | continue; |
251 | } | |
252 | s.setBlocking(); | |
a683e8bd | 253 | writen2(s.getHandle(), msg.c_str(), msg.size()); |
3565320b RG |
254 | } |
255 | catch(std::exception& e) { | |
256 | warnlog("Problem sending carbon data: %s", e.what()); | |
68ee58b6 | 257 | } |
68ee58b6 | 258 | } |
259 | } | |
68ee58b6 | 260 | } |
261 | catch(std::exception& e) | |
262 | { | |
263 | errlog("Carbon thread died: %s", e.what()); | |
68ee58b6 | 264 | } |
265 | catch(PDNSException& e) | |
266 | { | |
267 | errlog("Carbon thread died, PDNSException: %s", e.reason); | |
68ee58b6 | 268 | } |
269 | catch(...) | |
270 | { | |
271 | errlog("Carbon thread died"); | |
68ee58b6 | 272 | } |