prepare for the release of rrdtool-1.2.20
[rrdtool.git] / src / rrd_dump.c
1 /*****************************************************************************
2  * RRDtool 1.2.20  Copyright by Tobi Oetiker, 1997-2007
3  *****************************************************************************
4  * rrd_dump  Display a RRD
5  *****************************************************************************
6  * $Id$
7  * $Log$
8  * Revision 1.7  2004/05/25 20:53:21  oetiker
9  * prevent small leak when resources are exhausted -- Mike Slifcak
10  *
11  * Revision 1.6  2004/05/25 20:51:49  oetiker
12  * Update displayed copyright messages to be consistent. -- Mike Slifcak
13  *
14  * Revision 1.5  2003/02/13 07:05:27  oetiker
15  * Find attached the patch I promised to send to you. Please note that there
16  * are three new source files (src/rrd_is_thread_safe.h, src/rrd_thread_safe.c
17  * and src/rrd_not_thread_safe.c) and the introduction of librrd_th. This
18  * library is identical to librrd, but it contains support code for per-thread
19  * global variables currently used for error information only. This is similar
20  * to how errno per-thread variables are implemented.  librrd_th must be linked
21  * alongside of libpthred
22  *
23  * There is also a new file "THREADS", holding some documentation.
24  *
25  * -- Peter Stamfest <peter@stamfest.at>
26  *
27  * Revision 1.4  2002/02/01 20:34:49  oetiker
28  * fixed version number and date/time
29  *
30  * Revision 1.3  2001/03/10 23:54:39  oetiker
31  * Support for COMPUTE data sources (CDEF data sources). Removes the RPN
32  * parser and calculator from rrd_graph and puts then in a new file,
33  * rrd_rpncalc.c. Changes to core files rrd_create and rrd_update. Some
34  * clean-up of aberrant behavior stuff, including a bug fix.
35  * Documentation update (rrdcreate.pod, rrdupdate.pod). Change xml format.
36  * -- Jake Brutlag <jakeb@corp.webtv.net>
37  *
38  * Revision 1.2  2001/03/04 13:01:55  oetiker
39  *
40  * Revision 1.1.1.1  2001/02/25 22:25:05  oetiker
41  * checkin
42  *
43  *****************************************************************************/
44 #include "rrd_tool.h"
45 #include "rrd_rpncalc.h"
46
47 #if !(defined(NETWARE) || defined(WIN32))
48 extern char *tzname[2];
49 #endif
50
51 int
52 rrd_dump(int argc, char **argv) 
53 {
54     int                 rc;
55
56     if (argc < 2) {
57         rrd_set_error("Not enough arguments");
58         return -1;
59     }
60
61     if (argc == 3)
62     {
63       rc = rrd_dump_r(argv[1], argv[2]);
64     }
65     else
66     {
67       rc = rrd_dump_r(argv[1], NULL);                   
68     }
69
70     return rc;
71 }
72
73 int
74 rrd_dump_r(const char *filename, char *outname)    
75 {   
76     unsigned int i,ii,ix,iii=0;
77     time_t       now;
78     char         somestring[255];
79     rrd_value_t  my_cdp;
80     long         rra_base, rra_start, rra_next;
81     FILE        *in_file;
82                 FILE                            *out_file;
83     rrd_t        rrd;
84     rrd_value_t  value;
85     struct tm    tm;
86     if(rrd_open(filename, &in_file,&rrd, RRD_READONLY)==-1){
87         rrd_free(&rrd);
88         return(-1);
89     }
90
91     out_file = NULL;
92     if (outname)
93     {
94       if (!(out_file = fopen(outname, "w")))
95       {
96         return (-1);      
97       }
98     }
99     else 
100     {
101       out_file = stdout;
102     }
103                 
104     fputs("<!-- Round Robin Database Dump -->", out_file);
105     fputs("<rrd>", out_file);
106     fprintf(out_file, "\t<version> %s </version>\n",RRD_VERSION);
107     fprintf(out_file, "\t<step> %lu </step> <!-- Seconds -->\n",rrd.stat_head->pdp_step);
108 #if HAVE_STRFTIME
109     localtime_r(&rrd.live_head->last_up, &tm);
110     strftime(somestring,200,"%Y-%m-%d %H:%M:%S %Z",
111              &tm);
112 #else
113 # error "Need strftime"
114 #endif
115     fprintf(out_file, "\t<lastupdate> %ld </lastupdate> <!-- %s -->\n\n",
116            rrd.live_head->last_up,somestring);
117     for(i=0;i<rrd.stat_head->ds_cnt;i++){
118            fprintf(out_file, "\t<ds>\n");
119            fprintf(out_file, "\t\t<name> %s </name>\n",rrd.ds_def[i].ds_nam);
120            fprintf(out_file, "\t\t<type> %s </type>\n",rrd.ds_def[i].dst);
121        if (dst_conv(rrd.ds_def[i].dst) != DST_CDEF) {
122           fprintf(out_file, "\t\t<minimal_heartbeat> %lu </minimal_heartbeat>\n",rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt);
123               if (isnan(rrd.ds_def[i].par[DS_min_val].u_val)){
124                   fprintf(out_file, "\t\t<min> NaN </min>\n");
125               } else {
126                   fprintf(out_file, "\t\t<min> %0.10e </min>\n",rrd.ds_def[i].par[DS_min_val].u_val);
127               }
128               if (isnan(rrd.ds_def[i].par[DS_max_val].u_val)){
129                   fprintf(out_file, "\t\t<max> NaN </max>\n");
130               } else {
131                   fprintf(out_file, "\t\t<max> %0.10e </max>\n",rrd.ds_def[i].par[DS_max_val].u_val);
132               }
133        } else { /* DST_CDEF */
134               char *str=NULL;
135               rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),rrd.ds_def,&str);
136               fprintf(out_file, "\t\t<cdef> %s </cdef>\n", str);
137               free(str);
138            }
139            fprintf(out_file, "\n\t\t<!-- PDP Status -->\n");
140            fprintf(out_file, "\t\t<last_ds> %s </last_ds>\n",rrd.pdp_prep[i].last_ds);
141            if (isnan(rrd.pdp_prep[i].scratch[PDP_val].u_val)){
142               fprintf(out_file, "\t\t<value> NaN </value>\n");
143            } else {
144               fprintf(out_file, "\t\t<value> %0.10e </value>\n",rrd.pdp_prep[i].scratch[PDP_val].u_val);
145            }
146               fprintf(out_file, "\t\t<unknown_sec> %lu </unknown_sec>\n",
147                       rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt);
148         
149               fprintf(out_file, "\t</ds>\n\n");
150        }
151
152     fputs("<!-- Round Robin Archives -->", out_file);
153
154     rra_base=ftell(in_file);    
155     rra_next = rra_base;
156
157     for(i=0;i<rrd.stat_head->rra_cnt;i++){
158         
159         long timer=0;
160         rra_start= rra_next;
161         rra_next +=  ( rrd.stat_head->ds_cnt
162                       * rrd.rra_def[i].row_cnt
163                       * sizeof(rrd_value_t));
164         fprintf(out_file, "\t<rra>\n");
165         fprintf(out_file, "\t\t<cf> %s </cf>\n",rrd.rra_def[i].cf_nam);
166         fprintf(out_file, "\t\t<pdp_per_row> %lu </pdp_per_row> <!-- %lu seconds -->\n\n",
167                rrd.rra_def[i].pdp_cnt, rrd.rra_def[i].pdp_cnt
168                *rrd.stat_head->pdp_step);
169         /* support for RRA parameters */
170         fprintf(out_file, "\t\t<params>\n");
171         switch(cf_conv(rrd.rra_def[i].cf_nam)) {
172         case CF_HWPREDICT:
173            fprintf(out_file, "\t\t<hw_alpha> %0.10e </hw_alpha>\n", 
174                   rrd.rra_def[i].par[RRA_hw_alpha].u_val);
175            fprintf(out_file, "\t\t<hw_beta> %0.10e </hw_beta>\n", 
176                   rrd.rra_def[i].par[RRA_hw_beta].u_val);
177            fprintf(out_file, "\t\t<dependent_rra_idx> %lu </dependent_rra_idx>\n",
178                   rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
179            break;
180         case CF_SEASONAL:
181         case CF_DEVSEASONAL:
182            fprintf(out_file, "\t\t<seasonal_gamma> %0.10e </seasonal_gamma>\n", 
183                   rrd.rra_def[i].par[RRA_seasonal_gamma].u_val);
184            fprintf(out_file, "\t\t<seasonal_smooth_idx> %lu </seasonal_smooth_idx>\n",
185                   rrd.rra_def[i].par[RRA_seasonal_smooth_idx].u_cnt);
186            fprintf(out_file, "\t\t<dependent_rra_idx> %lu </dependent_rra_idx>\n",
187                   rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
188            break;
189         case CF_FAILURES:
190            fprintf(out_file, "\t\t<delta_pos> %0.10e </delta_pos>\n", 
191                   rrd.rra_def[i].par[RRA_delta_pos].u_val);
192            fprintf(out_file, "\t\t<delta_neg> %0.10e </delta_neg>\n", 
193                   rrd.rra_def[i].par[RRA_delta_neg].u_val);
194            fprintf(out_file, "\t\t<window_len> %lu </window_len>\n",
195                   rrd.rra_def[i].par[RRA_window_len].u_cnt);
196            fprintf(out_file, "\t\t<failure_threshold> %lu </failure_threshold>\n",
197                   rrd.rra_def[i].par[RRA_failure_threshold].u_cnt);
198                   /* fall thru */
199         case CF_DEVPREDICT:
200            fprintf(out_file, "\t\t<dependent_rra_idx> %lu </dependent_rra_idx>\n",
201                   rrd.rra_def[i].par[RRA_dependent_rra_idx].u_cnt);
202            break;
203         case CF_AVERAGE:
204         case CF_MAXIMUM:
205         case CF_MINIMUM:
206         case CF_LAST:
207         default:
208            fprintf(out_file, "\t\t<xff> %0.10e </xff>\n", rrd.rra_def[i].par[RRA_cdp_xff_val].u_val);
209            break;
210         }
211         fprintf(out_file, "\t\t</params>\n");
212         fprintf(out_file, "\t\t<cdp_prep>\n");
213         for(ii=0;ii<rrd.stat_head->ds_cnt;ii++){
214                 unsigned long ivalue;
215                 fprintf(out_file, "\t\t\t<ds>\n");
216                 /* support for exporting all CDP parameters */
217                 /* parameters common to all CFs */
218                     /* primary_val and secondary_val do not need to be saved between updates
219                          * so strictly speaking they could be omitted.
220                          * However, they can be useful for diagnostic purposes, so are included here. */
221                 value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt
222                            +ii].scratch[CDP_primary_val].u_val;
223                         if (isnan(value)) {
224                            fprintf(out_file, "\t\t\t<primary_value> NaN </primary_value>\n");
225                         } else {
226                            fprintf(out_file, "\t\t\t<primary_value> %0.10e </primary_value>\n", value);
227                         }
228                 value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_secondary_val].u_val;
229                         if (isnan(value)) {
230                            fprintf(out_file, "\t\t\t<secondary_value> NaN </secondary_value>\n");
231                         } else {
232                            fprintf(out_file, "\t\t\t<secondary_value> %0.10e </secondary_value>\n", value);
233                         }
234                 switch(cf_conv(rrd.rra_def[i].cf_nam)) {
235                 case CF_HWPREDICT:
236                 value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_intercept].u_val;
237                         if (isnan(value)) {
238                            fprintf(out_file, "\t\t\t<intercept> NaN </intercept>\n");
239                         } else {
240                            fprintf(out_file, "\t\t\t<intercept> %0.10e </intercept>\n", value);
241                         }
242                 value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_last_intercept].u_val;
243                         if (isnan(value)) {
244                            fprintf(out_file, "\t\t\t<last_intercept> NaN </last_intercept>\n");
245                         } else {
246                            fprintf(out_file, "\t\t\t<last_intercept> %0.10e </last_intercept>\n", value);
247                         }
248                 value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_slope].u_val;
249                         if (isnan(value)) {
250                            fprintf(out_file, "\t\t\t<slope> NaN </slope>\n");
251                         } else {
252                            fprintf(out_file, "\t\t\t<slope> %0.10e </slope>\n", value);
253                         }
254                 value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_last_slope].u_val;
255                         if (isnan(value)) {
256                            fprintf(out_file, "\t\t\t<last_slope> NaN </last_slope>\n");
257                         } else {
258                            fprintf(out_file, "\t\t\t<last_slope> %0.10e </last_slope>\n", value);
259                         }
260                         ivalue = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_null_count].u_cnt;
261                         fprintf(out_file, "\t\t\t<nan_count> %lu </nan_count>\n", ivalue);
262                         ivalue = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_last_null_count].u_cnt;
263                         fprintf(out_file, "\t\t\t<last_nan_count> %lu </last_nan_count>\n", ivalue);
264                         break;
265                 case CF_SEASONAL:
266                 case CF_DEVSEASONAL:
267                 value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_seasonal].u_val;
268                         if (isnan(value)) {
269                            fprintf(out_file, "\t\t\t<seasonal> NaN </seasonal>\n");
270                         } else {
271                            fprintf(out_file, "\t\t\t<seasonal> %0.10e </seasonal>\n", value);
272                         }
273                 value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_hw_last_seasonal].u_val;
274                         if (isnan(value)) {
275                            fprintf(out_file, "\t\t\t<last_seasonal> NaN </last_seasonal>\n");
276                         } else {
277                            fprintf(out_file, "\t\t\t<last_seasonal> %0.10e </last_seasonal>\n", value);
278                         }
279                 ivalue = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_init_seasonal].u_cnt;
280                         fprintf(out_file, "\t\t\t<init_flag> %lu </init_flag>\n", ivalue);
281                         break;
282                 case CF_DEVPREDICT:
283                         break;
284                 case CF_FAILURES:
285                     {
286             unsigned short vidx;
287                         char *violations_array = (char *) ((void*) 
288                            rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch);
289                         fprintf(out_file, "\t\t\t<history> ");
290                         for (vidx = 0; vidx < rrd.rra_def[i].par[RRA_window_len].u_cnt; ++vidx)
291                         {
292                                 fprintf(out_file, "%d",violations_array[vidx]);
293                         }
294                         fprintf(out_file, " </history>\n");
295                         }
296                         break;
297                 case CF_AVERAGE:
298                 case CF_MAXIMUM:
299                 case CF_MINIMUM:
300                 case CF_LAST:
301                 default:
302                 value = rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_val].u_val;
303                         if (isnan(value)) {
304                            fprintf(out_file, "\t\t\t<value> NaN </value>\n");
305                         } else {
306                            fprintf(out_file, "\t\t\t<value> %0.10e </value>\n", value);
307                         }
308                     fprintf(out_file, "\t\t\t<unknown_datapoints> %lu </unknown_datapoints>\n",
309                        rrd.cdp_prep[i*rrd.stat_head->ds_cnt+ii].scratch[CDP_unkn_pdp_cnt].u_cnt);
310                         break;
311                 }
312         fprintf(out_file, "\t\t\t</ds>\n");      
313     }
314         fprintf(out_file, "\t\t</cdp_prep>\n");
315
316         fprintf(out_file, "\t\t<database>\n");
317         fseek(in_file,(rra_start
318                        +(rrd.rra_ptr[i].cur_row+1)
319                        * rrd.stat_head->ds_cnt
320                        * sizeof(rrd_value_t)),SEEK_SET);
321         timer = - (rrd.rra_def[i].row_cnt-1);
322         ii=rrd.rra_ptr[i].cur_row;
323         for(ix=0;ix<rrd.rra_def[i].row_cnt;ix++){           
324             ii++;
325             if (ii>=rrd.rra_def[i].row_cnt) {
326                 fseek(in_file,rra_start,SEEK_SET);
327                 ii=0; /* wrap if max row cnt is reached */
328             }
329             now = (rrd.live_head->last_up 
330                    - rrd.live_head->last_up 
331                    % (rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step)) 
332                 + (timer*rrd.rra_def[i].pdp_cnt*rrd.stat_head->pdp_step);
333
334             timer++;
335 #if HAVE_STRFTIME
336             localtime_r(&now, &tm);
337             strftime(somestring,200,"%Y-%m-%d %H:%M:%S %Z", &tm);
338 #else
339 # error "Need strftime"
340 #endif
341             fprintf(out_file, "\t\t\t<!-- %s / %d --> <row>",somestring,(int)now);
342             for(iii=0;iii<rrd.stat_head->ds_cnt;iii++){                  
343                 fread(&my_cdp,sizeof(rrd_value_t),1,in_file);           
344                 if (isnan(my_cdp)){
345                   fprintf(out_file, "<v> NaN </v>");
346                 } else {
347                   fprintf(out_file, "<v> %0.10e </v>",my_cdp);
348                 };
349             }
350             fprintf(out_file, "</row>\n");
351         }
352         fprintf(out_file, "\t\t</database>\n\t</rra>\n");
353         
354     }
355     fprintf(out_file, "</rrd>\n");
356     rrd_free(&rrd);
357     fclose(in_file);
358     if (out_file != stdout)
359     {
360       fclose(out_file);
361     }
362     return(0);
363 }
364
365
366
367