]>
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) { | |
0affb140 | 90 | string serverName = state->name.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 RG |
93 | str<<base<<"queries" << ' ' << state->queries.load() << " " << now << "\r\n"; |
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"; |
2609f6e2 RG |
123 | str<<base<<"tcpdiedreadingquery" << ' '<< front->tcpDiedReadingQuery.load() << " " << now << "\r\n"; |
124 | str<<base<<"tcpdiedsendingresponse" << ' '<< front->tcpDiedSendingResponse.load() << " " << now << "\r\n"; | |
125 | str<<base<<"tcpgaveup" << ' '<< front->tcpGaveUp.load() << " " << now << "\r\n"; | |
126 | str<<base<<"tcpclientimeouts" << ' '<< front->tcpClientTimeouts.load() << " " << now << "\r\n"; | |
127 | str<<base<<"tcpdownstreamtimeouts" << ' '<< front->tcpDownstreamTimeouts.load() << " " << now << "\r\n"; | |
cff9aa03 RG |
128 | str<<base<<"tcpcurrentconnections" << ' '<< front->tcpCurrentConnections.load() << " " << now << "\r\n"; |
129 | str<<base<<"tcpavgqueriesperconnection" << ' '<< front->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n"; | |
130 | str<<base<<"tcpavgconnectionduration" << ' '<< front->tcpAvgConnectionDuration.load() << " " << now << "\r\n"; | |
3565320b | 131 | } |
a8b5b7a7 | 132 | |
a9c2e4ab RG |
133 | auto localPools = g_pools.getLocal(); |
134 | for (const auto& entry : *localPools) { | |
9e9be156 RG |
135 | string poolName = entry.first; |
136 | boost::replace_all(poolName, ".", "_"); | |
137 | if (poolName.empty()) { | |
138 | poolName = "_default_"; | |
139 | } | |
813b0ba9 | 140 | const string base = namespace_name + "." + hostname + "." + instance_name + ".pools." + poolName + "."; |
9e9be156 | 141 | const std::shared_ptr<ServerPool> pool = entry.second; |
a1b1a29d RG |
142 | str<<base<<"servers" << " " << pool->countServers(false) << " " << now << "\r\n"; |
143 | str<<base<<"servers-up" << " " << pool->countServers(true) << " " << now << "\r\n"; | |
9e9be156 RG |
144 | if (pool->packetCache != nullptr) { |
145 | const auto& cache = pool->packetCache; | |
146 | str<<base<<"cache-size" << " " << cache->getMaxEntries() << " " << now << "\r\n"; | |
147 | str<<base<<"cache-entries" << " " << cache->getEntriesCount() << " " << now << "\r\n"; | |
148 | str<<base<<"cache-hits" << " " << cache->getHits() << " " << now << "\r\n"; | |
149 | str<<base<<"cache-misses" << " " << cache->getMisses() << " " << now << "\r\n"; | |
150 | str<<base<<"cache-deferred-inserts" << " " << cache->getDeferredInserts() << " " << now << "\r\n"; | |
151 | str<<base<<"cache-deferred-lookups" << " " << cache->getDeferredLookups() << " " << now << "\r\n"; | |
152 | str<<base<<"cache-lookup-collisions" << " " << cache->getLookupCollisions() << " " << now << "\r\n"; | |
153 | str<<base<<"cache-insert-collisions" << " " << cache->getInsertCollisions() << " " << now << "\r\n"; | |
cc8cefe1 | 154 | str<<base<<"cache-ttl-too-shorts" << " " << cache->getTTLTooShorts() << " " << now << "\r\n"; |
9e9be156 RG |
155 | } |
156 | } | |
786e4d8c | 157 | |
fbf14b03 RG |
158 | #ifdef HAVE_DNS_OVER_HTTPS |
159 | { | |
a8b5b7a7 | 160 | std::map<std::string,uint64_t> dohFrontendDuplicates; |
fbf14b03 RG |
161 | const string base = "dnsdist." + hostname + ".main.doh."; |
162 | for(const auto& doh : g_dohlocals) { | |
163 | string name = doh->d_local.toStringWithPort(); | |
164 | boost::replace_all(name, ".", "_"); | |
165 | boost::replace_all(name, ":", "_"); | |
166 | boost::replace_all(name, "[", "_"); | |
167 | boost::replace_all(name, "]", "_"); | |
168 | ||
a8b5b7a7 | 169 | auto dupPair = dohFrontendDuplicates.insert({name, 1}); |
131df256 | 170 | if (!dupPair.second) { |
a8b5b7a7 | 171 | name = name + "_" + std::to_string(dupPair.first->second); |
131df256 | 172 | ++(dupPair.first->second); |
a8b5b7a7 RG |
173 | } |
174 | ||
fbf14b03 RG |
175 | vector<pair<const char*, const std::atomic<uint64_t>&>> v{ |
176 | {"http-connects", doh->d_httpconnects}, | |
5bbcbea0 RG |
177 | {"http1-queries", doh->d_http1Stats.d_nbQueries}, |
178 | {"http2-queries", doh->d_http2Stats.d_nbQueries}, | |
179 | {"http1-200-responses", doh->d_http1Stats.d_nb200Responses}, | |
180 | {"http2-200-responses", doh->d_http2Stats.d_nb200Responses}, | |
181 | {"http1-400-responses", doh->d_http1Stats.d_nb400Responses}, | |
182 | {"http2-400-responses", doh->d_http2Stats.d_nb400Responses}, | |
183 | {"http1-403-responses", doh->d_http1Stats.d_nb403Responses}, | |
184 | {"http2-403-responses", doh->d_http2Stats.d_nb403Responses}, | |
185 | {"http1-500-responses", doh->d_http1Stats.d_nb500Responses}, | |
186 | {"http2-500-responses", doh->d_http2Stats.d_nb500Responses}, | |
187 | {"http1-502-responses", doh->d_http1Stats.d_nb502Responses}, | |
188 | {"http2-502-responses", doh->d_http2Stats.d_nb502Responses}, | |
189 | {"http1-other-responses", doh->d_http1Stats.d_nbOtherResponses}, | |
190 | {"http2-other-responses", doh->d_http2Stats.d_nbOtherResponses}, | |
fbf14b03 RG |
191 | {"tls10-queries", doh->d_tls10queries}, |
192 | {"tls11-queries", doh->d_tls11queries}, | |
193 | {"tls12-queries", doh->d_tls12queries}, | |
194 | {"tls13-queries", doh->d_tls13queries}, | |
195 | {"tls-unknown-queries", doh->d_tlsUnknownqueries}, | |
196 | {"get-queries", doh->d_getqueries}, | |
197 | {"post-queries", doh->d_postqueries}, | |
198 | {"bad-requests", doh->d_badrequests}, | |
199 | {"error-responses", doh->d_errorresponses}, | |
1ddac024 | 200 | {"redirect-responses", doh->d_redirectresponses}, |
fbf14b03 RG |
201 | {"valid-responses", doh->d_validresponses} |
202 | }; | |
203 | ||
204 | for(const auto& item : v) { | |
205 | str<<base<<name<<"."<<item.first << " " << item.second << " " << now <<"\r\n"; | |
206 | } | |
207 | } | |
208 | } | |
209 | #endif /* HAVE_DNS_OVER_HTTPS */ | |
210 | ||
786e4d8c RS |
211 | { |
212 | WriteLock wl(&g_qcount.queryLock); | |
213 | std::string qname; | |
214 | for(auto &record: g_qcount.records) { | |
215 | qname = record.first; | |
216 | boost::replace_all(qname, ".", "_"); | |
217 | str<<"dnsdist.querycount." << qname << ".queries " << record.second << " " << now << "\r\n"; | |
218 | } | |
219 | g_qcount.records.clear(); | |
220 | } | |
221 | ||
3565320b | 222 | const string msg = str.str(); |
a1a787dc | 223 | |
3565320b RG |
224 | int ret = waitForRWData(s.getHandle(), false, 1 , 0); |
225 | if(ret <= 0 ) { | |
226 | vinfolog("Unable to write data to carbon server on %s: %s", server.toStringWithPort(), (ret<0 ? strerror(errno) : "Timeout")); | |
227 | continue; | |
228 | } | |
229 | s.setBlocking(); | |
a683e8bd | 230 | writen2(s.getHandle(), msg.c_str(), msg.size()); |
3565320b RG |
231 | } |
232 | catch(std::exception& e) { | |
233 | warnlog("Problem sending carbon data: %s", e.what()); | |
68ee58b6 | 234 | } |
68ee58b6 | 235 | } |
236 | } | |
68ee58b6 | 237 | } |
238 | catch(std::exception& e) | |
239 | { | |
240 | errlog("Carbon thread died: %s", e.what()); | |
68ee58b6 | 241 | } |
242 | catch(PDNSException& e) | |
243 | { | |
244 | errlog("Carbon thread died, PDNSException: %s", e.reason); | |
68ee58b6 | 245 | } |
246 | catch(...) | |
247 | { | |
248 | errlog("Carbon thread died"); | |
68ee58b6 | 249 | } |