1 /**
2  * @file annot.c
3  * @brief Implementation of the annotation set object.
4  * @class ln_annot annot.h
5  *//*
6  * Copyright 2011 by Rainer Gerhards and Adiscon GmbH.
7  *
8  * Modified by Pavel Levshin (pavel@levshin.spb.ru) in 2013
9  *
10  * This file is part of liblognorm.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Sannott, Fifth Floor, Boston, MA  02110-1301  USA
25  *
26  * A copy of the LGPL v2.1 can be found in the file "COPYING" in this distribution.
27  */
28 #include "config.h"
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <assert.h>
34 #include <ctype.h>
35 #include <libestr.h>
36 
37 #include "lognorm.h"
38 #include "samp.h"
39 #include "annot.h"
40 #include "internal.h"
41 
42 ln_annotSet*
ln_newAnnotSet(ln_ctx ctx)43 ln_newAnnotSet(ln_ctx ctx)
44 {
45 	ln_annotSet *as;
46 
47 	if((as = calloc(1, sizeof(struct ln_annotSet_s))) == NULL)
48 		goto done;
49 	as->ctx = ctx;
50 done:	return as;
51 }
52 
53 
54 void
ln_deleteAnnotSet(ln_annotSet * as)55 ln_deleteAnnotSet(ln_annotSet *as)
56 {
57 	ln_annot *node, *nextnode;
58 	if(as == NULL)
59 		goto done;
60 
61 	for(node = as->aroot; node != NULL; node = nextnode) {
62 		nextnode = node->next;
63 		ln_deleteAnnot(node);
64 	}
65 	free(as);
66 done:	return;
67 }
68 
69 
70 ln_annot*
ln_findAnnot(ln_annotSet * as,es_str_t * tag)71 ln_findAnnot(ln_annotSet *as, es_str_t *tag)
72 {
73 	ln_annot *annot;
74 	if(as == NULL) {
75 		annot = NULL;
76 		goto done;
77 	}
78 
79 	for(  annot = as->aroot
80 	    ; annot != NULL && es_strcmp(annot->tag, tag)
81 	    ; annot = annot->next) {
82 		; /* do nothing, just search... */
83 	}
84 done:	return annot;
85 }
86 
87 
88 /**
89  * Combine two annotations.
90  * @param[in] annot currently existing and surviving annotation
91  * @param[in] add   annotation to be added. This will be destructed
92  *                  as part of the process.
93  * @returns 0 if ok, something else otherwise
94  */
95 static int
ln_combineAnnot(ln_annot * annot,ln_annot * add)96 ln_combineAnnot(ln_annot *annot, ln_annot *add)
97 {
98 	int r = 0;
99 	ln_annot_op *op, *nextop;
100 
101 	for(op = add->oproot; op != NULL; op = nextop) {
102 		CHKR(ln_addAnnotOp(annot, op->opc, op->name, op->value));
103 		nextop = op->next;
104 		free(op);
105 	}
106 	es_deleteStr(add->tag);
107 	free(add);
108 
109 done:	return r;
110 }
111 
112 
113 int
ln_addAnnotToSet(ln_annotSet * as,ln_annot * annot)114 ln_addAnnotToSet(ln_annotSet *as, ln_annot *annot)
115 {
116 	int r = 0;
117 	ln_annot *aexist;
118 	assert(annot->tag != NULL);
119 	aexist = ln_findAnnot(as, annot->tag);
120 	if(aexist == NULL) {
121 		/* does not yet exist, simply store new annot */
122 		annot->next = as->aroot;
123 		as->aroot = annot;
124 	} else { /* annotation already exists, combine */
125 		r = ln_combineAnnot(aexist, annot);
126 	}
127 	return r;
128 }
129 
130 
131 ln_annot*
ln_newAnnot(es_str_t * tag)132 ln_newAnnot(es_str_t *tag)
133 {
134 	ln_annot *annot;
135 
136 	if((annot = calloc(1, sizeof(struct ln_annot_s))) == NULL)
137 		goto done;
138 	annot->tag = tag;
139 done:	return annot;
140 }
141 
142 
143 void
ln_deleteAnnot(ln_annot * annot)144 ln_deleteAnnot(ln_annot *annot)
145 {
146 	ln_annot_op *op, *nextop;
147 	if(annot == NULL)
148 		goto done;
149 
150 	es_deleteStr(annot->tag);
151 	for(op = annot->oproot; op != NULL; op = nextop) {
152 		es_deleteStr(op->name);
153 		if(op->value != NULL)
154 			es_deleteStr(op->value);
155 		nextop = op->next;
156 		free(op);
157 	}
158 	free(annot);
159 done:	return;
160 }
161 
162 
163 int
ln_addAnnotOp(ln_annot * annot,ln_annot_opcode opc,es_str_t * name,es_str_t * value)164 ln_addAnnotOp(ln_annot *annot, ln_annot_opcode opc, es_str_t *name, es_str_t *value)
165 {
166 	int r = -1;
167 	ln_annot_op *node;
168 
169 	if((node = calloc(1, sizeof(struct ln_annot_op_s))) == NULL)
170 		goto done;
171 	node->opc = opc;
172 	node->name = name;
173 	node->value = value;
174 
175 	if(annot->oproot != NULL) {
176 		node->next = annot->oproot;
177 	}
178 	annot->oproot = node;
179 	r = 0;
180 
181 done:	return r;
182 }
183 
184 
185 /* annotate the event with a specific tag. helper to keep code
186  * small and easy to follow.
187  */
188 static inline int
ln_annotateEventWithTag(ln_ctx ctx,struct json_object * json,es_str_t * tag)189 ln_annotateEventWithTag(ln_ctx ctx, struct json_object *json, es_str_t *tag)
190 {
191 	int r=0;
192 	ln_annot *annot;
193 	ln_annot_op *op;
194 	struct json_object *field;
195 	char *cstr;
196 
197 	if (NULL == (annot = ln_findAnnot(ctx->pas, tag)))
198 		goto done;
199 	for(op = annot->oproot ; op != NULL ; op = op->next) {
200 		if(op->opc == ln_annot_ADD) {
201 			CHKN(cstr = ln_es_str2cstr(&op->value));
202 			CHKN(field = json_object_new_string(cstr));
203 			CHKN(cstr = ln_es_str2cstr(&op->name));
204 			json_object_object_add(json, cstr, field);
205 		} else {
206 			// TODO: implement
207 		}
208 	}
209 
210 done: 	return r;
211 }
212 
213 
214 int
ln_annotate(ln_ctx ctx,struct json_object * json,struct json_object * tagbucket)215 ln_annotate(ln_ctx ctx, struct json_object *json, struct json_object *tagbucket)
216 {
217 	int r = 0;
218 	es_str_t *tag;
219 	struct json_object *tagObj;
220 	const char *tagCstr;
221 	int i;
222 
223 	ln_dbgprintf(ctx, "ln_annotate called [aroot=%p]", ctx->pas->aroot);
224 	/* shortcut: terminate immediately if nothing to do... */
225 	if(ctx->pas->aroot == NULL)
226 		goto done;
227 
228 	/* iterate over tagbucket */
229 	for (i = json_object_array_length(tagbucket) - 1; i >= 0; i--) {
230 		CHKN(tagObj = json_object_array_get_idx(tagbucket, i));
231 		CHKN(tagCstr = json_object_get_string(tagObj));
232 		ln_dbgprintf(ctx, "ln_annotate, current tag %d, cstr %s", i, tagCstr);
233 		CHKN(tag = es_newStrFromCStr(tagCstr, strlen(tagCstr)));
234 		CHKR(ln_annotateEventWithTag(ctx, json, tag));
235 		es_deleteStr(tag);
236 	}
237 
238 done:	return r;
239 }
240