make build with gcc7
[liblognorm.git] / src / normalizer.c
1 /**
2  * @file normalizer.c
3  * @brief A small tool to normalize data.
4  *
5  * This is the most basic example demonstrating how to use liblognorm.
6  * It loads log samples from the files specified on the command line,
7  * reads to-be-normalized data from stdin and writes the normalized
8  * form to stdout. Besides being an example, it also carries out useful
9  * processing.
10  *
11  * @author Rainer Gerhards <rgerhards@adiscon.com>
12  *
13  *//*
14  * liblognorm - a fast samples-based log normalization library
15  * Copyright 2010 by Rainer Gerhards and Adiscon GmbH.
16  *
17  * This file is part of liblognorm.
18  *
19  * This library is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU Lesser General Public
21  * License as published by the Free Software Foundation; either
22  * version 2.1 of the License, or (at your option) any later version.
23  *
24  * This library is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27  * Lesser General Public License for more details.
28  *
29  * You should have received a copy of the GNU Lesser General Public
30  * License along with this library; if not, write to the Free Software
31  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
32  *
33  * A copy of the LGPL v2.1 can be found in the file "COPYING" in this distribution.
34  */
35 #include <stdio.h>
36 #include <string.h>
37 #include <getopt.h>
38 #include <libestr.h>
39 #include <libee/libee.h>
40 #include "liblognorm.h"
41 #include "ptree.h"
42 #include "lognorm.h"
43
44 static ln_ctx ctx;
45 static ee_ctx eectx;
46
47 static int verbose = 0;
48 static int parsedOnly = 0;      /**< output unparsed messages? */
49 static FILE *fpDOT;
50 static es_str_t *encFmt = NULL; /**< a format string for encoder use */
51 static es_str_t *mandatoryTag = NULL; /**< tag which must be given so that mesg will
52                                            be output. NULL=all */
53 static enum { f_syslog, f_json, f_xml, f_csv } outfmt = f_syslog;
54
55 void
56 dbgCallBack(void __attribute__((unused)) *cookie, char *msg,
57             size_t __attribute__((unused)) lenMsg)
58 {
59         printf("liblognorm: %s\n", msg);
60 }
61
62 void errout(char *errmsg)
63 {
64         fprintf(stderr, "%s\n", errmsg);
65         exit(1);
66 }
67
68
69 /* param str is just a performance enhancement, which saves us re-creation
70  * of the string on every call.
71  */
72 static inline void
73 outputEvent(struct ee_event *event, es_str_t **str)
74 {
75         char *cstr;
76         es_emptyStr(*str);
77         switch(outfmt) {
78         case f_json:
79                 ee_fmtEventToJSON(event, str);
80                 break;
81         case f_syslog:
82                 ee_fmtEventToRFC5424(event, str);
83                 break;
84         case f_xml:
85                 ee_fmtEventToXML(event, str);
86                 break;
87         case f_csv:
88                 ee_fmtEventToCSV(event, str, encFmt);
89                 break;
90         }
91         cstr = es_str2cstr(*str, NULL);
92         if(verbose > 0) printf("normalized: '%s'\n", cstr);
93         printf("%s\n", cstr);
94         free(cstr);
95 }
96
97
98 /* normalize input data
99  */
100 void
101 normalize(void)
102 {
103         FILE *fp = stdin;
104         char buf[10*1024];
105         es_str_t *str;
106         struct ee_event *event = NULL;
107         es_str_t *constUnparsed;
108         long long unsigned numUnparsed = 0;
109         long long unsigned numWrongTag = 0;
110
111         constUnparsed = es_newStrFromBuf("unparsed-data", sizeof("unparsed-data") - 1);
112
113         while((fgets(buf, sizeof(buf), fp)) != NULL) {
114                 buf[strlen(buf)-1] = '\0';
115                 if(strlen(buf) > 0 && buf[strlen(buf)-1] == '\r')
116                         buf[strlen(buf)-1] = '\0';
117                 if(verbose > 0) printf("To normalize: '%s'\n", buf);
118                 str = es_newStrFromCStr(buf, strlen(buf));
119                 ln_normalize(ctx, str, &event);
120                 //printf("normalize result: %d\n", ln_normalizeRec(ctx, ctx->ptree, str, 0, &event));
121                 if(event != NULL) {
122                         if(   mandatoryTag == NULL
123                            || (mandatoryTag != NULL && ee_EventHasTag(event, mandatoryTag))) {
124                                 if(   parsedOnly == 1
125                                    && ee_getEventField(event, constUnparsed) != NULL){
126                                         numUnparsed++;
127                                 } else {
128                                         outputEvent(event, &str);
129                                 }
130                         } else {
131                                 numWrongTag++;
132                         }
133                         ee_deleteEvent(event);
134                         event = NULL;
135                 }
136                 es_deleteStr(str);
137         }
138         if(numUnparsed > 0)
139                 fprintf(stderr, "%llu unparsable entries\n", numUnparsed);
140         if(numWrongTag > 0)
141                 fprintf(stderr, "%llu entries with wrong tag dropped\n", numWrongTag);
142 }
143
144
145 /**
146  * Generate a command file for the GNU DOT tools.
147  */
148 static void
149 genDOT()
150 {
151         es_str_t *str;
152
153         str = es_newStr(1024);
154         ln_genDotPTreeGraph(ctx->ptree, &str);
155         fwrite(es_getBufAddr(str), 1, es_strlen(str), fpDOT);
156 }
157
158
159 int main(int argc, char *argv[])
160 {
161         int opt;
162         char *repository = NULL;
163         
164         while((opt = getopt(argc, argv, "d:e:r:E:vpt:")) != -1) {
165                 switch (opt) {
166                 case 'd': /* generate DOT file */
167                         if(!strcmp(optarg, "")) {
168                                 fpDOT = stdout;
169                         } else {
170                                 if((fpDOT = fopen(optarg, "w")) == NULL) {
171                                         errout("cannot open DOT file");
172                                 }
173                         }
174                 case 'v':
175                         verbose++;
176                         break;
177                 case 'E': /* encoder-specific format string (will be validated by encoder) */ 
178                         encFmt = es_newStrFromCStr(optarg, strlen(optarg));
179                         break;
180                 case 'p':
181                         parsedOnly = 1;
182                         break;
183                 case 'e': /* encoder to use */
184                         if(!strcmp(optarg, "json")) {
185                                 outfmt = f_json;
186                         } else if(!strcmp(optarg, "xml")) {
187                                 outfmt = f_xml;
188                         } else if(!strcmp(optarg, "csv")) {
189                                 outfmt = f_csv;
190                         }
191                         break;
192                 case 'r': /* rule base to use */
193                         repository = optarg;
194                         break;
195                 case 't': /* if given, only messages tagged with the argument
196                              are output */
197                         mandatoryTag = es_newStrFromCStr(optarg, strlen(optarg));
198                         break;
199                 }
200         }
201         
202         if(repository == NULL) {
203                 errout("samples repository must be given");
204         }
205
206         if((ctx = ln_initCtx()) == NULL) {
207                 errout("Could not initialize liblognorm context");
208         }
209
210         if((eectx = ee_initCtx()) == NULL) {
211                 errout("Could not initialize libee context");
212         }
213
214         if(verbose) {
215                 ln_setDebugCB(ctx, dbgCallBack, NULL);
216                 ln_enableDebug(ctx, 1);
217         }
218         ln_setEECtx(ctx, eectx);
219
220         ln_loadSamples(ctx, repository);
221
222         if(verbose > 0)
223                 printf("number of tree nodes: %d\n", ctx->nNodes);
224
225         if(fpDOT != NULL) {
226                 genDOT();
227                 exit(1);
228         }
229
230         if(verbose > 2) ln_displayPTree(ctx->ptree, 0);
231
232         normalize();
233
234         ln_exitCtx(ctx);
235         return 0;
236 }