root/src/noit_check_log_helpers.c

Revision 3fd0aac519a54f829d5813c8c121dd9947786e17, 10.6 kB (checked in by Al Tobey <al@ooyala.com>, 3 years ago)

initialize dlen to make gcc happy

  • 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) return -1;
134       memcpy(buf_out, rawbuff, rawlen);
135       break;
136   }
137
138   return 0;
139 }
140
141 int
142 noit_stats_snprint_metric_value(char *b, int l, metric_t *m) {
143   int rv;
144   if(!m->metric_value.s) { /* they are all null */
145     rv = snprintf(b, l, "[[null]]");
146   }
147   else {
148     switch(m->metric_type) {
149       case METRIC_INT32:
150         rv = snprintf(b, l, "%d", *(m->metric_value.i)); break;
151       case METRIC_UINT32:
152         rv = snprintf(b, l, "%u", *(m->metric_value.I)); break;
153       case METRIC_INT64:
154         rv = snprintf(b, l, "%lld", (long long int)*(m->metric_value.l)); break;
155       case METRIC_UINT64:
156         rv = snprintf(b, l, "%llu",
157                       (long long unsigned int)*(m->metric_value.L)); break;      case METRIC_DOUBLE:
158         rv = snprintf(b, l, "%.12e", *(m->metric_value.n)); break;
159       case METRIC_STRING:
160         rv = snprintf(b, l, "%s", m->metric_value.s); break;
161       default:
162         return -1;
163     }
164   }
165   return rv;
166 }
167
168 int
169 noit_check_log_b_to_sm(const char *line, int len, char ***out) {
170   Bundle *bundle = NULL;
171   noit_compression_type_t ctype;
172   unsigned int ulen;
173   int i, size, cnt = 0, has_status = 0;
174   const char *cp1, *cp2, *rest, *error_str = NULL;
175   char *timestamp, *uuid_str, *target, *module, *name, *ulen_str;
176   unsigned char *raw_protobuf = NULL;
177
178   *out = NULL;
179   if(len < 3) return 0;
180   if(line[0] != 'B' || line[2] != '\t') return 0;
181   switch(line[1]) {
182     case '1': ctype = NOIT_COMPRESS_ZLIB; break;
183     case '2': ctype = NOIT_COMPRESS_NONE; break;
184     default: return 0;
185   }
186
187   /* All good, and we're off to the races */
188   line += 3; len -= 3;
189   cp1 = line;
190 #define SET_FIELD_FROM_BUNDLE(tgt) do { \
191   if(*cp1 == '\0') { error_str = "short line @ " #tgt; goto bad_line; } \
192   cp2 = strnstrn("\t", 1, cp1, len - (cp1 - line)); \
193   if(cp2 == NULL) { error_str = "no tab after " #tgt; goto bad_line; } \
194   tgt = (char *)alloca(cp2 - cp1 + 1); \
195   if(!tgt) { error_str = "alloca failed for " #tgt; goto bad_line; } \
196   memcpy(tgt, cp1, cp2 - cp1); \
197   tgt[cp2 - cp1] = '\0'; \
198   cp1 = cp2 + 1; \
199 } while(0)
200   SET_FIELD_FROM_BUNDLE(timestamp);
201   SET_FIELD_FROM_BUNDLE(uuid_str);
202   SET_FIELD_FROM_BUNDLE(target);
203   SET_FIELD_FROM_BUNDLE(module);
204   SET_FIELD_FROM_BUNDLE(name);
205   SET_FIELD_FROM_BUNDLE(ulen_str);
206   rest = cp1;
207
208   ulen = strtoul(ulen_str, NULL, 10);
209   raw_protobuf = malloc(ulen);
210   if(!raw_protobuf) {
211     noitL(noit_error, "bundle decode: memory exhausted\n");
212     goto bad_line;
213   }
214   if(noit_check_log_bundle_decompress_b64(ctype,
215                                           rest, len - (rest - line),
216                                           (char *)raw_protobuf,
217                                           ulen)) {
218     noitL(noit_error, "bundle decode: failed to decompress\n");
219     goto bad_line;
220   }
221   /* decode the protobuf */
222   bundle = bundle__unpack(&protobuf_c_system_allocator, ulen, raw_protobuf);
223   if(!bundle) {
224     noitL(noit_error, "bundle decode: protobuf invalid\n");
225     goto bad_line;
226   }
227   noitL(noit_error, "ZOMG -> data (%lld metrics)\n",
228         (long long int)bundle->n_metrics);
229   has_status = bundle->status ? 1 : 0;
230   cnt = bundle->n_metrics;
231   *out = calloc(sizeof(**out), cnt + has_status);
232   if(!*out) { error_str = "memory exhaustion"; goto bad_line; }
233   if(has_status) {
234     Status *status = bundle->status;
235     /* build out status line */
236     size = 2 /* S\t */ + strlen(timestamp) + 1 /* \t */ + strlen(uuid_str) +
237            5 /* \tG\tA\t */ + 11 /* max(strlen(duration)) */ +
238            1 /* \t */ +
239            (status->status ? strlen(status->status) : 8 /* [[null]] */) +
240            1 /* \0 */;
241     **out = malloc(size);
242     snprintf(**out, size, "S\t%s\t%s\t%c\t%c\t%d\t%s",
243              timestamp, uuid_str, status->state, status->available,
244              status->duration, status->status ? status->status : "[[null]]");
245   }
246   /* build our metric lines */
247   for(i=0; i<cnt; i++) {
248     Metric *metric = bundle->metrics[i];
249     metric_t m;
250     char scratch[64], *value_str;;
251     int value_size = 0;
252
253     m.metric_name = metric->name;
254     m.metric_type = metric->metrictype;
255     m.metric_value.vp = NULL;
256     scratch[0] = '\0';
257     value_str = scratch;
258     switch(m.metric_type) {
259       case METRIC_INT32:
260         m.metric_value.i = &metric->valuei32;
261         noit_stats_snprint_metric_value(scratch, 64, &m);
262         value_size = strlen(scratch);
263         break;
264       case METRIC_UINT32:
265         m.metric_value.I = &metric->valueui32;
266         noit_stats_snprint_metric_value(scratch, 64, &m);
267         value_size = strlen(scratch);
268         break;
269       case METRIC_INT64:
270         m.metric_value.l = &metric->valuei64;
271         noit_stats_snprint_metric_value(scratch, 64, &m);
272         value_size = strlen(scratch);
273         break;
274       case METRIC_UINT64:
275         m.metric_value.L = &metric->valueui64;
276         noit_stats_snprint_metric_value(scratch, 64, &m);
277         value_size = strlen(scratch);
278         break;
279       case METRIC_DOUBLE:
280         m.metric_value.n = &metric->valuedbl;
281         noit_stats_snprint_metric_value(scratch, 64, &m);
282         value_size = strlen(scratch);
283         break;
284       case METRIC_STRING:
285         m.metric_value.s = metric->valuestr ? metric->valuestr : "[[null]]";
286         value_str = metric->valuestr ? metric->valuestr : "[[null]]";
287         value_size = strlen(value_str);
288         break;
289       default:
290         break;
291     }
292     if(value_size == 0) continue; /* WTF, bad metric_type? */
293
294     size = 2 /* M\t */ + strlen(timestamp) + 1 /* \t */ +
295            strlen(uuid_str) + 1 /* \t */ + strlen(metric->name) +
296            3 /* \t<type>\t */ + value_size + 1 /* \0 */;
297     (*out)[i+has_status] = malloc(size);
298     snprintf((*out)[i+has_status], size, "M\t%s\t%s\t%s\t%c\t%s",
299              timestamp, uuid_str, metric->name, m.metric_type, value_str);
300   }
301   goto good_line;
302
303  bad_line:
304   if(*out) {
305     int i;
306     for(i=0; i<cnt + has_status; i++) if((*out)[i]) free((*out)[i]);
307     free(*out);
308     *out = NULL;
309   }
310   if(error_str) noitL(noit_error, "bundle: bad line due to %s\n", error_str);
311  good_line:
312   if(bundle) bundle__free_unpacked(bundle, &protobuf_c_system_allocator);
313   if(raw_protobuf) free(raw_protobuf);
314   return cnt;
315 }
Note: See TracBrowser for help on using the browser.