Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * rrd_thread.cpp - RRD Thread 00004 * 00005 * Created: Fri Dec 17 00:32:57 2010 00006 * Copyright 2006-2010 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include "rrd_thread.h" 00024 00025 #include <core/exceptions/system.h> 00026 #include <core/threading/scoped_rwlock.h> 00027 #include <utils/misc/string_conversions.h> 00028 #include <utils/system/file.h> 00029 #include <cstdio> 00030 #include <cstdlib> 00031 #include <cstdarg> 00032 #include <cstring> 00033 #include <rrd.h> 00034 00035 using namespace fawkes; 00036 00037 /** @class RRDThread "rrd_thread.h" 00038 * RRD Thread. 00039 * This thread maintains an active connection to RRD and provides an 00040 * aspect to access RRD to make it convenient for other threads to use 00041 * RRD. 00042 * 00043 * @author Tim Niemueller 00044 */ 00045 00046 /** Constructor. */ 00047 RRDThread::RRDThread() 00048 : Thread("RRDThread", Thread::OPMODE_CONTINUOUS), 00049 AspectProviderAspect("RRDAspect", &__rrd_aspect_inifin), 00050 __rrd_aspect_inifin(this) 00051 { 00052 set_prepfin_conc_loop(true); 00053 } 00054 00055 00056 /** Destructor. */ 00057 RRDThread::~RRDThread() 00058 { 00059 } 00060 00061 00062 void 00063 RRDThread::init() 00064 { 00065 __cfg_graph_interval = 30.; 00066 try { 00067 __cfg_graph_interval = config->get_float("/plugins/rrd/graph_interval"); 00068 } catch (Exception &e) {} 00069 00070 __time_wait = new TimeWait(clock, time_sec_to_usec(__cfg_graph_interval)); 00071 } 00072 00073 00074 void 00075 RRDThread::finalize() 00076 { 00077 } 00078 00079 00080 void 00081 RRDThread::loop() 00082 { 00083 __time_wait->mark_start(); 00084 generate_graphs(); 00085 __time_wait->wait_systime(); 00086 } 00087 00088 00089 /** Generate all graphs. */ 00090 void 00091 RRDThread::generate_graphs() 00092 { 00093 ScopedRWLock lock(__graphs.rwlock(), ScopedRWLock::LOCK_READ); 00094 00095 std::vector<fawkes::RRDGraphDefinition *>::iterator g; 00096 for (g = __graphs.begin(); g != __graphs.end(); ++g) { 00097 size_t argc = 0; 00098 const char **argv = (*g)->get_argv(argc); 00099 00100 //logger->log_debug(name(), "rrd_graph arguments:"); 00101 //for (size_t j = 0; j < argc; ++j) { 00102 // logger->log_debug(name(), " %zu: %s", j, argv[j]); 00103 //} 00104 00105 rrd_clear_error(); 00106 rrd_info_t *i = rrd_graph_v(argc, (char **)argv); 00107 if (i == NULL) { 00108 throw Exception("Creating graph %s (for RRD %s) failed: %s", 00109 (*g)->get_name(), (*g)->get_rrd_def()->get_name(), 00110 rrd_get_error()); 00111 } 00112 rrd_info_free(i); 00113 } 00114 } 00115 00116 void 00117 RRDThread::add_rrd(RRDDefinition *rrd_def) 00118 { 00119 // generate filename 00120 char *filename; 00121 if (asprintf(&filename, "%s/%s.rrd", ".", rrd_def->get_name()) == -1) { 00122 throw OutOfMemoryException("Failed to creat filename for RRD %s", 00123 rrd_def->get_name()); 00124 } 00125 rrd_def->set_filename(filename); 00126 free(filename); 00127 00128 if (! File::exists(rrd_def->get_filename()) || rrd_def->get_recreate()) { 00129 std::string size_s = StringConversions::to_string(rrd_def->get_step_sec()); 00130 00131 // build parameter array 00132 // "create" filename --step STEP --start START DS... RRA... 00133 size_t rrd_argc = 6 + rrd_def->get_ds().size() + rrd_def->get_rra().size(); 00134 const char *rrd_argv[rrd_argc]; 00135 size_t i = 0; 00136 rrd_argv[i++] = "create"; 00137 rrd_argv[i++] = rrd_def->get_filename(); 00138 rrd_argv[i++] = "--step"; 00139 rrd_argv[i++] = size_s.c_str(); 00140 rrd_argv[i++] = "--start"; 00141 rrd_argv[i++] = "0"; 00142 00143 std::vector<RRDDataSource>::const_iterator d; 00144 for (d = rrd_def->get_ds().begin(); 00145 d != rrd_def->get_ds().end() && i < rrd_argc; 00146 ++d) 00147 { 00148 rrd_argv[i++] = d->to_string(); 00149 } 00150 00151 std::vector<RRDArchive>::const_iterator a; 00152 for (a = rrd_def->get_rra().begin(); 00153 a != rrd_def->get_rra().end() && i < rrd_argc; 00154 ++a) 00155 { 00156 rrd_argv[i++] = a->to_string(); 00157 } 00158 00159 //logger->log_debug(name(), "rrd_create arguments:"); 00160 //for (size_t j = 0; j < i; ++j) { 00161 // logger->log_debug(name(), " %zu: %s", j, rrd_argv[j]); 00162 //} 00163 00164 // Create RRD file 00165 rrd_clear_error(); 00166 if (rrd_create(i, (char **)rrd_argv) == -1) { 00167 throw Exception("Creating RRD %s failed: %s", 00168 rrd_def->get_name(), rrd_get_error()); 00169 } 00170 } 00171 00172 ScopedRWLock lock(__rrds.rwlock()); 00173 RWLockVector<fawkes::RRDDefinition *>::iterator r; 00174 for (r = __rrds.begin(); r != __rrds.end(); ++r) { 00175 if (strcmp((*r)->get_name(), rrd_def->get_name()) == 0) { 00176 throw Exception("RRD with name %s has already been registered", 00177 rrd_def->get_name()); 00178 } 00179 } 00180 00181 rrd_def->set_rrd_manager(this); 00182 __rrds.push_back(rrd_def); 00183 } 00184 00185 void 00186 RRDThread::remove_rrd(RRDDefinition *rrd_def) 00187 { 00188 ScopedRWLock rrds_lock(__rrds.rwlock()); 00189 RWLockVector<fawkes::RRDDefinition *>::iterator r; 00190 for (r = __rrds.begin(); r != __rrds.end(); ++r) { 00191 if (strcmp((*r)->get_name(), rrd_def->get_name()) == 0) { 00192 __rrds.erase(r); 00193 break; 00194 } 00195 } 00196 00197 ScopedRWLock graph_lock(__graphs.rwlock()); 00198 bool graphs_modified = false; 00199 do { 00200 graphs_modified = false; 00201 RWLockVector<fawkes::RRDGraphDefinition *>::iterator g; 00202 for (g = __graphs.begin(); g != __graphs.end(); ++g) { 00203 if (strcmp((*g)->get_rrd_def()->get_name(), rrd_def->get_name()) == 0) { 00204 __graphs.erase(g); 00205 graphs_modified = true; 00206 break; 00207 } 00208 } 00209 } while (graphs_modified); 00210 } 00211 00212 void 00213 RRDThread::add_graph(RRDGraphDefinition *rrd_graph_def) 00214 { 00215 // generate filename 00216 char *filename; 00217 if (asprintf(&filename, "%s/%s.png", ".", 00218 rrd_graph_def->get_name()) == -1) { 00219 throw OutOfMemoryException("Failed to create filename for PNG %s", 00220 rrd_graph_def->get_name()); 00221 } 00222 rrd_graph_def->set_filename(filename); 00223 free(filename); 00224 00225 ScopedRWLock lock(__graphs.rwlock()); 00226 RWLockVector<fawkes::RRDGraphDefinition *>::iterator g; 00227 for (g = __graphs.begin(); g != __graphs.end(); ++g) { 00228 if (strcmp((*g)->get_name(), rrd_graph_def->get_name()) == 0) { 00229 throw Exception("RRD graph with name %s has already been registered", 00230 rrd_graph_def->get_name()); 00231 } 00232 } 00233 __graphs.push_back(rrd_graph_def); 00234 } 00235 00236 void 00237 RRDThread::add_data(const char *rrd_name, const char *format, ...) 00238 { 00239 ScopedRWLock lock(__rrds.rwlock(), ScopedRWLock::LOCK_READ); 00240 00241 std::vector<RRDDefinition *>::const_iterator d; 00242 for (d = __rrds.begin(); d != __rrds.end(); ++d) { 00243 RRDDefinition *rrd_def = *d; 00244 if (strcmp(rrd_name, rrd_def->get_name()) == 0) { 00245 char *data; 00246 va_list arg; 00247 va_start(arg, format); 00248 if (vasprintf(&data, format, arg) == -1) { 00249 va_end(arg); 00250 throw OutOfMemoryException("Failed to create data string for %s", 00251 rrd_name); 00252 } 00253 va_end(arg); 00254 00255 // filename data 00256 size_t rrd_argc = 3; 00257 const char *rrd_argv[rrd_argc]; 00258 size_t i = 0; 00259 rrd_argv[i++] = "update"; 00260 rrd_argv[i++] = rrd_def->get_filename(); 00261 rrd_argv[i++] = data; 00262 00263 //logger->log_debug(name(), "rrd_update arguments:"); 00264 //for (size_t j = 0; j < i; ++j) { 00265 // logger->log_debug(name(), " %zu: %s", j, rrd_argv[j]); 00266 //} 00267 00268 rrd_clear_error(); 00269 if (rrd_update(i, (char **)rrd_argv) == -1) { 00270 free(data); 00271 throw Exception("Failed to update RRD %s: %s", rrd_name, rrd_get_error()); 00272 } 00273 00274 free(data); 00275 return; 00276 } 00277 } 00278 00279 throw Exception("No RRD named %s registered", rrd_name); 00280 } 00281 00282 00283 const fawkes::RWLockVector<RRDDefinition *> & 00284 RRDThread::get_rrds() const 00285 { 00286 return __rrds; 00287 } 00288 00289 00290 const fawkes::RWLockVector<RRDGraphDefinition *> & 00291 RRDThread::get_graphs() const 00292 { 00293 return __graphs; 00294 }