root/src/noit_check_log_helpers.c

Revision 53a1d2f27f6f957022e9af4b56ff5f4eebb3b5ec, 10.7 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

OMG off-by-one. We were missing the last metric.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2011, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34 #include "noit_check.h"
35 #include "noit_check_log_helpers.h"
36 #include <stdio.h>
37 #include <zlib.h>
38 #include "utils/noit_b64.h"
39 #include "utils/noit_str.h"
40 #include "utils/noit_log.h"
41 #include "bundle.pb-c.h"
42
43 int
44 noit_check_log_bundle_compress_b64(noit_compression_type_t ctype,
45                                    const char *buf_in,
46                                    unsigned int len_in,
47                                    char ** buf_out,
48                                    unsigned int * len_out) {
49   uLong initial_dlen, dlen = 0;
50   char *compbuff = NULL, *b64buff;
51
52   // Compress saves 25% of space (ex 470 -> 330)
53   switch(ctype) {
54     case NOIT_COMPRESS_ZLIB:
55       /* Compress */
56       initial_dlen = dlen = compressBound((uLong)len_in);
57       compbuff = malloc(initial_dlen);
58       if(!compbuff) return -1;
59       if(Z_OK != compress2((Bytef *)compbuff, &dlen,
60                            (Bytef *)buf_in, len_in, 9)) {
61         noitL(noit_error, "Error compressing bundled metrics.\n");
62         free(compbuff);
63         return -1;
64       }
65       break;
66     case NOIT_COMPRESS_NONE:
67       // Or don't
68       dlen = (uLong)len_in;
69       compbuff = (char *)buf_in;
70       break;
71   }
72
73   /* Encode */
74   // Problems with the calculation?
75   initial_dlen = ((dlen + 2) / 3 * 4);
76   b64buff = malloc(initial_dlen);
77   if (!b64buff) {
78     if(ctype == NOIT_COMPRESS_ZLIB) free(compbuff);
79     return -1;
80   }
81   dlen = noit_b64_encode((unsigned char *)compbuff, dlen,
82                          (char *)b64buff, initial_dlen);
83   if(ctype == NOIT_COMPRESS_ZLIB) free(compbuff);
84   if(dlen == 0) {
85     noitL(noit_error, "Error base64'ing bundled metrics.\n");
86     free(b64buff);
87     return -1;
88   }
89   *buf_out = b64buff;
90   *len_out = (unsigned int)dlen;
91   return 0;
92 }
93
94 int
95 noit_check_log_bundle_decompress_b64(noit_compression_type_t ctype,
96                                      const char *buf_in,
97                                      unsigned int len_in,
98                                      char *buf_out,
99                                      unsigned int len_out) {
100   int rv;
101   uLong initial_dlen, dlen, rawlen;
102   char *compbuff, *rawbuff;
103
104   /* Decode */
105   initial_dlen = ((len_in / 4) * 3);
106   compbuff = malloc(initial_dlen);
107   if (!compbuff) return -1;
108   dlen = noit_b64_decode((char *)buf_in, len_in,
109                          (unsigned char *)compbuff, initial_dlen);
110   if(dlen == 0) {
111     noitL(noit_error, "Error base64'ing bundled metrics.\n");
112     free(compbuff);
113     return -1;
114   }
115
116   switch(ctype) {
117     case NOIT_COMPRESS_ZLIB:
118       /* Decompress */
119       rawlen = len_out;
120       if(Z_OK != (rv = uncompress((Bytef *)buf_out, &rawlen,
121                                   (Bytef *)compbuff, dlen)) ||
122          rawlen != len_out) {
123         noitL(noit_error, "Error decompressing bundle: %d (%u != %u).\n",
124               rv, (unsigned int)rawlen, (unsigned int)len_out);
125         free(compbuff);
126         return -1;
127       }
128       break;
129     case NOIT_COMPRESS_NONE:
130       // Or don't
131       rawlen = (uLong)dlen;
132       rawbuff = compbuff;
133       if(rawlen != len_out) {
134         if(compbuff) free(compbuff);
135         return -1;
136       }
137       memcpy(buf_out, rawbuff, rawlen);
138       break;
139   }
140
141   if(compbuff) free(compbuff);
142   return 0;
143 }
144
145 int
146 noit_stats_snprint_metric_value(char *b, int l, metric_t *m) {
147   int rv;
148   if(!m->metric_value.s) { /* they are all null */
149     rv = snprintf(b, l, "[[null]]");
150   }
151   else {
152     switch(m->metric_type) {
153       case METRIC_INT32:
154         rv = snprintf(b, l, "%d", *(m->metric_value.i)); break;
155       case METRIC_UINT32:
156         rv = snprintf(b, l, "%u", *(m->metric_value.I)); break;
157       case METRIC_INT64:
158         rv = snprintf(b, l, "%lld", (long long int)*(m->metric_value.l)); break;
159       case METRIC_UINT64:
160         rv = snprintf(b, l, "%llu",
161                       (long long unsigned int)*(m->metric_value.L)); break;      case METRIC_DOUBLE:
162         rv = snprintf(b, l, "%.12e", *(m->metric_value.n)); break;
163       case METRIC_STRING:
164         rv = snprintf(b, l, "%s", m->metric_value.s); break;
165       default:
166         return -1;
167     }
168   }
169   return rv;
170 }
171
172 int
173 noit_check_log_b_to_sm(const char *line, int len, char ***out) {
174   Bundle *bundle = NULL;
175   noit_compression_type_t ctype;
176   unsigned int ulen;
177   int i, size, cnt = 0, has_status = 0;
178   const char *cp1, *cp2, *rest, *error_str = NULL;
179   char *timestamp, *uuid_str, *target, *module, *name, *ulen_str;
180   unsigned char *raw_protobuf = NULL;
181
182   *out = NULL;
183   if(len < 3) return 0;
184   if(line[0] != 'B' || line[2] != '\t') return 0;
185   switch(line[1]) {
186     case '1': ctype = NOIT_COMPRESS_ZLIB; break;
187     case '2': ctype = NOIT_COMPRESS_NONE; break;
188     default: return 0;
189   }
190
191   /* All good, and we're off to the races */
192   line += 3; len -= 3;
193   cp1 = line;
194 #define SET_FIELD_FROM_BUNDLE(tgt) do { \
195   if(*cp1 == '\0') { error_str = "short line @ " #tgt; goto bad_line; } \
196   cp2 = strnstrn("\t", 1, cp1, len - (cp1 - line)); \
197   if(cp2 == NULL) { error_str = "no tab after " #tgt; goto bad_line; } \
198   tgt = (char *)alloca(cp2 - cp1 + 1); \
199   if(!tgt) { error_str = "alloca failed for " #tgt; goto bad_line; } \
200   memcpy(tgt, cp1, cp2 - cp1); \
201   tgt[cp2 - cp1] = '\0'; \
202   cp1 = cp2 + 1; \
203 } while(0)
204   SET_FIELD_FROM_BUNDLE(timestamp);
205   SET_FIELD_FROM_BUNDLE(uuid_str);
206   SET_FIELD_FROM_BUNDLE(target);
207   SET_FIELD_FROM_BUNDLE(module);
208   SET_FIELD_FROM_BUNDLE(name);
209   SET_FIELD_FROM_BUNDLE(ulen_str);
210   rest = cp1;
211
212   ulen = strtoul(ulen_str, NULL, 10);
213   raw_protobuf = malloc(ulen);
214   if(!raw_protobuf) {
215     noitL(noit_error, "bundle decode: memory exhausted\n");
216     goto bad_line;
217   }
218   if(noit_check_log_bundle_decompress_b64(ctype,
219                                           rest, len - (rest - line),
220                                           (char *)raw_protobuf,
221                                           ulen)) {
222     noitL(noit_error, "bundle decode: failed to decompress\n");
223     goto bad_line;
224   }
225   /* decode the protobuf */
226   bundle = bundle__unpack(&protobuf_c_system_allocator, ulen, raw_protobuf);
227   if(!bundle) {
228     noitL(noit_error, "bundle decode: protobuf invalid\n");
229     goto bad_line;
230   }
231   has_status = bundle->status ? 1 : 0;
232   cnt = bundle->n_metrics;
233   *out = calloc(sizeof(**out), cnt + has_status);
234   if(!*out) { error_str = "memory exhaustion"; goto bad_line; }
235   if(has_status) {
236     Status *status = bundle->status;
237     /* build out status line */
238     size = 2 /* S\t */ + strlen(timestamp) + 1 /* \t */ + strlen(uuid_str) +
239            5 /* \tG\tA\t */ + 11 /* max(strlen(duration)) */ +
240            1 /* \t */ +
241            (status->status ? strlen(status->status) : 8 /* [[null]] */) +
242            1 /* \0 */;
243     **out = malloc(size);
244     snprintf(**out, size, "S\t%s\t%s\t%c\t%c\t%d\t%s",
245              timestamp, uuid_str, status->state, status->available,
246              status->duration, status->status ? status->status : "[[null]]");
247   }
248   /* build our metric lines */
249   for(i=0; i<cnt; i++) {
250     Metric *metric = bundle->metrics[i];
251     metric_t m;
252     char scratch[64], *value_str;;
253     int value_size = 0;
254
255     m.metric_name = metric->name;
256     m.metric_type = metric->metrictype;
257     m.metric_value.vp = NULL;
258     scratch[0] = '\0';
259     value_str = scratch;
260     switch(m.metric_type) {
261       case METRIC_INT32:
262         m.metric_value.i = &metric->valuei32;
263         noit_stats_snprint_metric_value(scratch, 64, &m);
264         value_size = strlen(scratch);
265         break;
266       case METRIC_UINT32:
267         m.metric_value.I = &metric->valueui32;
268         noit_stats_snprint_metric_value(scratch, 64, &m);
269         value_size = strlen(scratch);
270         break;
271       case METRIC_INT64:
272         m.metric_value.l = &metric->valuei64;
273         noit_stats_snprint_metric_value(scratch, 64, &m);
274         value_size = strlen(scratch);
275         break;
276       case METRIC_UINT64:
277         m.metric_value.L = &metric->valueui64;
278         noit_stats_snprint_metric_value(scratch, 64, &m);
279         value_size = strlen(scratch);
280         break;
281       case METRIC_DOUBLE:
282         m.metric_value.n = &metric->valuedbl;
283         noit_stats_snprint_metric_value(scratch, 64, &m);
284         value_size = strlen(scratch);
285         break;
286       case METRIC_STRING:
287         m.metric_value.s = metric->valuestr ? metric->valuestr : "[[null]]";
288         value_str = metric->valuestr ? metric->valuestr : "[[null]]";
289         value_size = strlen(value_str);
290         break;
291       default:
292         break;
293     }
294     if(value_size == 0) continue; /* WTF, bad metric_type? */
295
296     size = 2 /* M\t */ + strlen(timestamp) + 1 /* \t */ +
297            strlen(uuid_str) + 1 /* \t */ + strlen(metric->name) +
298            3 /* \t<type>\t */ + value_size + 1 /* \0 */;
299     (*out)[i+has_status] = malloc(size);
300     snprintf((*out)[i+has_status], size, "M\t%s\t%s\t%s\t%c\t%s",
301              timestamp, uuid_str, metric->name, m.metric_type, value_str);
302   }
303   goto good_line;
304
305  bad_line:
306   if(*out) {
307     int i;
308     for(i=0; i<cnt + has_status; i++) if((*out)[i]) free((*out)[i]);
309     free(*out);
310     *out = NULL;
311   }
312   if(error_str) noitL(noit_error, "bundle: bad line due to %s\n", error_str);
313  good_line:
314   if(bundle) bundle__free_unpacked(bundle, &protobuf_c_system_allocator);
315   if(raw_protobuf) free(raw_protobuf);
316   return cnt + has_status;
317 }
Note: See TracBrowser for help on using the browser.