]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-carbon.cc
Sphinx 1.8.0 seems broken, use any other version available instead
[thirdparty/pdns.git] / pdns / dnsdist-carbon.cc
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 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "iputils.hh"
26 #include "dolog.hh"
27 #include "sstuff.hh"
28
29 #include "namespaces.hh"
30 #undef L
31 #include "dnsdist.hh"
32
33 GlobalStateHolder<vector<CarbonConfig> > g_carbon;
34 static time_t s_start=time(0);
35 uint64_t uptimeOfProcess(const std::string& str)
36 {
37 return time(0) - s_start;
38 }
39
40 void* carbonDumpThread()
41 try
42 {
43 auto localCarbon = g_carbon.getLocal();
44 for(int numloops=0;;++numloops) {
45 if(localCarbon->empty()) {
46 sleep(1);
47 continue;
48 }
49 /* this is wrong, we use the interval of the first server
50 for every single one of them */
51 if(numloops) {
52 const unsigned int interval = localCarbon->at(0).interval;
53 sleep(interval);
54 }
55
56 for (const auto& conf : *localCarbon) {
57 const auto& server = conf.server;
58 std::string hostname = conf.ourname;
59 if(hostname.empty()) {
60 char tmp[80];
61 memset(tmp, 0, sizeof(tmp));
62 gethostname(tmp, sizeof(tmp));
63 char *p = strchr(tmp, '.');
64 if(p) *p=0;
65 hostname=tmp;
66 boost::replace_all(hostname, ".", "_");
67 }
68
69 try {
70 Socket s(server.sin4.sin_family, SOCK_STREAM);
71 s.setNonBlocking();
72 s.connect(server); // we do the connect so the attempt happens while we gather stats
73 ostringstream str;
74 time_t now=time(0);
75 for(const auto& e : g_stats.entries) {
76 str<<"dnsdist."<<hostname<<".main."<<e.first<<' ';
77 if(const auto& val = boost::get<DNSDistStats::stat_t*>(&e.second))
78 str<<(*val)->load();
79 else if (const auto& dval = boost::get<double*>(&e.second))
80 str<<**dval;
81 else
82 str<<(*boost::get<DNSDistStats::statfunction_t>(&e.second))(e.first);
83 str<<' '<<now<<"\r\n";
84 }
85 const auto states = g_dstates.getCopy();
86 for(const auto& state : states) {
87 string serverName = state->name.empty() ? (state->remote.toString() + ":" + std::to_string(state->remote.getPort())) : state->getName();
88 boost::replace_all(serverName, ".", "_");
89 const string base = "dnsdist." + hostname + ".main.servers." + serverName + ".";
90 str<<base<<"queries" << ' ' << state->queries.load() << " " << now << "\r\n";
91 str<<base<<"drops" << ' ' << state->reuseds.load() << " " << now << "\r\n";
92 str<<base<<"latency" << ' ' << (state->availability != DownstreamState::Availability::Down ? state->latencyUsec/1000.0 : 0) << " " << now << "\r\n";
93 str<<base<<"senderrors" << ' ' << state->sendErrors.load() << " " << now << "\r\n";
94 str<<base<<"outstanding" << ' ' << state->outstanding.load() << " " << now << "\r\n";
95 }
96 for(const auto& front : g_frontends) {
97 if (front->udpFD == -1 && front->tcpFD == -1)
98 continue;
99
100 string frontName = front->local.toString() + ":" + std::to_string(front->local.getPort()) + (front->udpFD >= 0 ? "_udp" : "_tcp");
101 boost::replace_all(frontName, ".", "_");
102 const string base = "dnsdist." + hostname + ".main.frontends." + frontName + ".";
103 str<<base<<"queries" << ' ' << front->queries.load() << " " << now << "\r\n";
104 }
105 const auto localPools = g_pools.getCopy();
106 for (const auto& entry : localPools) {
107 string poolName = entry.first;
108 boost::replace_all(poolName, ".", "_");
109 if (poolName.empty()) {
110 poolName = "_default_";
111 }
112 const string base = "dnsdist." + hostname + ".main.pools." + poolName + ".";
113 const std::shared_ptr<ServerPool> pool = entry.second;
114 str<<base<<"servers" << " " << pool->servers.size() << " " << now << "\r\n";
115 if (pool->packetCache != nullptr) {
116 const auto& cache = pool->packetCache;
117 str<<base<<"cache-size" << " " << cache->getMaxEntries() << " " << now << "\r\n";
118 str<<base<<"cache-entries" << " " << cache->getEntriesCount() << " " << now << "\r\n";
119 str<<base<<"cache-hits" << " " << cache->getHits() << " " << now << "\r\n";
120 str<<base<<"cache-misses" << " " << cache->getMisses() << " " << now << "\r\n";
121 str<<base<<"cache-deferred-inserts" << " " << cache->getDeferredInserts() << " " << now << "\r\n";
122 str<<base<<"cache-deferred-lookups" << " " << cache->getDeferredLookups() << " " << now << "\r\n";
123 str<<base<<"cache-lookup-collisions" << " " << cache->getLookupCollisions() << " " << now << "\r\n";
124 str<<base<<"cache-insert-collisions" << " " << cache->getInsertCollisions() << " " << now << "\r\n";
125 str<<base<<"cache-ttl-too-shorts" << " " << cache->getTTLTooShorts() << " " << now << "\r\n";
126 }
127 }
128
129 {
130 WriteLock wl(&g_qcount.queryLock);
131 std::string qname;
132 for(auto &record: g_qcount.records) {
133 qname = record.first;
134 boost::replace_all(qname, ".", "_");
135 str<<"dnsdist.querycount." << qname << ".queries " << record.second << " " << now << "\r\n";
136 }
137 g_qcount.records.clear();
138 }
139
140 const string msg = str.str();
141
142 int ret = waitForRWData(s.getHandle(), false, 1 , 0);
143 if(ret <= 0 ) {
144 vinfolog("Unable to write data to carbon server on %s: %s", server.toStringWithPort(), (ret<0 ? strerror(errno) : "Timeout"));
145 continue;
146 }
147 s.setBlocking();
148 writen2(s.getHandle(), msg.c_str(), msg.size());
149 }
150 catch(std::exception& e) {
151 warnlog("Problem sending carbon data: %s", e.what());
152 }
153 }
154 }
155 return 0;
156 }
157 catch(std::exception& e)
158 {
159 errlog("Carbon thread died: %s", e.what());
160 return 0;
161 }
162 catch(PDNSException& e)
163 {
164 errlog("Carbon thread died, PDNSException: %s", e.reason);
165 return 0;
166 }
167 catch(...)
168 {
169 errlog("Carbon thread died");
170 return 0;
171 }