]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/ws.cc
and the final bit of whitespace/tab cleanup
[thirdparty/pdns.git] / pdns / ws.cc
1 /*
2 Copyright (C) 2002 - 2007 PowerDNS.COM BV
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License version 2
6 as published by the Free Software Foundation
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 #include "utility.hh"
18 #include "ws.hh"
19 #include "webserver.hh"
20 #include "logger.hh"
21 #include "statbag.hh"
22 #include "misc.hh"
23 #include "arguments.hh"
24 #include "dns.hh"
25 #include <boost/format.hpp>
26
27 extern StatBag S;
28
29 StatWebServer::StatWebServer()
30 {
31 d_start=time(0);
32 d_min10=d_min5=d_min1=0;
33 }
34
35 void StatWebServer::go()
36 {
37 S.doRings();
38 pthread_create(&d_tid, 0, threadHelper, this);
39 pthread_create(&d_tid, 0, statThreadHelper, this);
40 }
41
42 void StatWebServer::statThread()
43 {
44 try {
45 for(;;) {
46 d_queries.submit(S.read("udp-queries"));
47 d_cachehits.submit(S.read("packetcache-hit"));
48 d_cachemisses.submit(S.read("packetcache-miss"));
49 d_qcachehits.submit(S.read("query-cache-hit"));
50 d_qcachemisses.submit(S.read("query-cache-miss"));
51 Utility::sleep(1);
52 }
53 }
54 catch(...) {
55 L<<Logger::Error<<"Webserver statThread caught an exception, dying"<<endl;
56 exit(1);
57 }
58 }
59
60 void *StatWebServer::statThreadHelper(void *p)
61 {
62 StatWebServer *sws=static_cast<StatWebServer *>(p);
63 sws->statThread();
64 return 0; // never reached
65 }
66
67
68 void *StatWebServer::threadHelper(void *p)
69 {
70 StatWebServer *sws=static_cast<StatWebServer *>(p);
71 sws->launch();
72 return 0; // never reached
73 }
74
75 void printtable(ostringstream &ret, const string &ringname, const string &title, int limit=10)
76 {
77 int tot=0;
78 int entries=0;
79 vector<pair <string,int> >ring=S.getRing(ringname);
80
81 for(vector<pair<string,int> >::const_iterator i=ring.begin(); i!=ring.end();++i) {
82 tot+=i->second;
83 entries++;
84 }
85
86
87 ret<<"<table border=1><tr><td colspan=3 bgcolor=#0000ff>"
88 "<a href=?ring="<<ringname<<"><font color=#ffffff>Top-"<<limit<<" of ";
89 ret<<entries<<": "<<title<<"</a></td>"<<endl;
90
91 ret<<"<tr><td colspan=3><table bgcolor=#ff0000 width=100%><tr><td align=left>"
92 "<a href=?resetring="<<ringname<<"><font color=#ffffff>Reset</a></td>";
93 ret<<"<td align=right>Resize: ";
94
95 int sizes[]={10,100,500,1000,10000,500000,0};
96 for(int i=0;sizes[i];++i) {
97 if(S.getRingSize(ringname)!=sizes[i])
98 ret<<"<a href=?resizering="<<ringname<<"&size="<<sizes[i]<<">"<<sizes[i]<<"</a> ";
99 else
100 ret<<"("<<sizes[i]<<") ";
101 }
102 ret<<"</td></table>"<<endl;
103
104
105 int printed=0;
106 for(vector<pair<string,int> >::const_iterator i=ring.begin();limit && i!=ring.end();++i,--limit) {
107 ret<<"<tr><td>"<<i->first<<"</td><td>"<<i->second<<"</td><td align=right>"<< StatWebServer::makePercentage(i->second*100.0/tot)<<"</td>"<<endl;
108 printed+=i->second;
109 }
110 ret<<"<tr><td colspan=3></td></tr>"<<endl;
111 if(printed!=tot)
112 ret<<"<tr><td><b>Rest:</b></td><td><b>"<<tot-printed<<"</b></td><td align=right><b>"<< StatWebServer::makePercentage((tot-printed)*100.0/tot)<<"</b></td>"<<endl;
113
114 ret<<"<tr><td><b>Total:</b></td><td><b>"<<tot<<"</td><td align=right><b>100%</b></td>";
115 ret<<"</table><p>"<<endl;
116 }
117
118 void StatWebServer::printvars(ostringstream &ret)
119 {
120 ret<<"<table border=1><tr><td colspan=3 bgcolor=#0000ff><font color=#ffffff>Variables</td>"<<endl;
121
122
123 vector<string>entries=S.getEntries();
124 for(vector<string>::const_iterator i=entries.begin();i!=entries.end();++i) {
125 ret<<"<tr><td>"<<*i<<"</td><td>"<<S.read(*i)<<"</td><td>"<<S.getDescrip(*i)<<"</td>"<<endl;
126 }
127 }
128
129 void StatWebServer::printargs(ostringstream &ret)
130 {
131 ret<<"<table border=1><tr><td colspan=3 bgcolor=#0000ff><font color=#ffffff>Arguments</td>"<<endl;
132
133 vector<string>entries=arg().list();
134 for(vector<string>::const_iterator i=entries.begin();i!=entries.end();++i) {
135 ret<<"<tr><td>"<<*i<<"</td><td>"<<arg()[*i]<<"</td><td>"<<arg().getHelp(*i)<<"</td>"<<endl;
136 }
137 }
138
139 string StatWebServer::makePercentage(const double& val)
140 {
141 return (boost::format("%.01f%%") % val).str();
142 }
143
144 string StatWebServer::indexfunction(const map<string,string> &varmap, void *ptr, bool *custom)
145 {
146
147 StatWebServer *sws=static_cast<StatWebServer *>(ptr);
148 map<string,string>rvarmap=varmap;
149 if(!rvarmap["resetring"].empty()){
150 *custom=true;
151 S.resetRing(rvarmap["resetring"]);
152 return "HTTP/1.1 301 Moved Permanently\nLocation: /\nConnection: close\n\n";
153 }
154 if(!rvarmap["resizering"].empty()){
155 *custom=true;
156 S.resizeRing(rvarmap["resizering"], atoi(rvarmap["size"].c_str()));
157 return "HTTP/1.1 301 Moved Permanently\nLocation: /\nConnection: close\n\n";
158 }
159
160 ostringstream ret;
161
162 ret<<"<html><head><title>PowerDNS Operational Monitor</title></head><body bgcolor=#ffffff>"<<endl;
163
164
165 ret<<"<h2>";
166 if(!arg()["config-name"].empty())
167 ret<<"["<<arg()["config-name"]<<"]";
168 if(rvarmap["ring"].empty())
169 ret<<"PDNS "VERSION" Main Page</h2>"<<endl;
170 else
171 ret<<"Details page</h2><a href=/>Back to main page</a><p>"<<endl;
172
173 time_t passed=time(0)-s_starttime;
174
175 ret<<"Uptime: ";
176 ret<<humanDuration(passed)<<endl;
177
178
179 ret<<"Queries/second, 1, 5, 10 minute averages: "<<setprecision(3)<<
180 sws->d_queries.get1()<<", "<<
181 sws->d_queries.get5()<<", "<<
182 sws->d_queries.get10()<<". Max queries/second: "<<sws->d_queries.getMax()<<
183 "<br>"<<endl;
184
185 if(sws->d_cachemisses.get10()+sws->d_cachehits.get10()>0)
186 ret<<"Cache hitrate, 1, 5, 10 minute averages: "<<
187 makePercentage((sws->d_cachehits.get1()*100.0)/((sws->d_cachehits.get1())+(sws->d_cachemisses.get1())))<<", "<<
188 makePercentage((sws->d_cachehits.get5()*100.0)/((sws->d_cachehits.get5())+(sws->d_cachemisses.get5())))<<", "<<
189 makePercentage((sws->d_cachehits.get10()*100.0)/((sws->d_cachehits.get10())+(sws->d_cachemisses.get10())))<<
190 "<br>"<<endl;
191
192 if(sws->d_qcachemisses.get10()+sws->d_qcachehits.get10()>0)
193 ret<<"Backend query cache hitrate, 1, 5, 10 minute averages: "<<setprecision(2)<<
194 makePercentage((sws->d_qcachehits.get1()*100.0)/((sws->d_qcachehits.get1())+(sws->d_qcachemisses.get1())))<<", "<<
195 makePercentage((sws->d_qcachehits.get5()*100.0)/((sws->d_qcachehits.get5())+(sws->d_qcachemisses.get5())))<<", "<<
196 makePercentage((sws->d_qcachehits.get10()*100.0)/((sws->d_qcachehits.get10())+(sws->d_qcachemisses.get10())))<<
197 "<br>"<<endl;
198
199 ret<<"Backend query load, 1, 5, 10 minute averages: "<<setprecision(3)<<
200 sws->d_qcachemisses.get1()<<", "<<
201 sws->d_qcachemisses.get5()<<", "<<
202 sws->d_qcachemisses.get10()<<". Max queries/second: "<<sws->d_qcachemisses.getMax()<<
203 "<br>"<<endl;
204
205 ret<<"Total queries: "<<S.read("udp-queries")<<". Question/answer latency: "<<S.read("latency")/1000.0<<"ms<p>"<<endl;
206 if(rvarmap["ring"].empty()) {
207 vector<string>entries=S.listRings();
208 for(vector<string>::const_iterator i=entries.begin();i!=entries.end();++i)
209 printtable(ret,*i,S.getRingTitle(*i));
210
211 sws->printvars(ret);
212 if(arg().mustDo("webserver-print-arguments"))
213 sws->printargs(ret);
214 }
215 else
216 printtable(ret,rvarmap["ring"],S.getRingTitle(rvarmap["ring"]),100);
217
218 ret<<"</body></html>"<<endl;
219
220 return ret.str();
221 }
222
223 void StatWebServer::launch()
224 {
225 try {
226 WebServer ws(arg()["webserver-address"], arg().asNum("webserver-port"),arg()["webserver-password"]);
227 ws.setCaller(this);
228 ws.registerHandler("",&indexfunction);
229 ws.go();
230 }
231 catch(...) {
232 L<<Logger::Error<<"StatWebserver thread caught an exception, dying"<<endl;
233 exit(1);
234 }
235 }