48f6f3c2 |
1 | /* The text dump facility needs to print headers before the trace set and |
2 | before each trace, to print each event, and to print statistics |
3 | after each trace. */ |
4 | |
f60d7a47 |
5 | #include <ltt/type.h> |
6 | #include <lttv/attribute.h> |
7 | #include <lttv/hook.h> |
8 | |
48f6f3c2 |
9 | void init(int argc, char **argv) |
10 | { |
11 | lttv_attributes *a; |
12 | lttv_hooks *before, *after; |
13 | |
14 | a = lttv_global_attributes(); |
15 | before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, |
16 | "hooks/trace_set/before"); |
17 | after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, |
18 | "hooks/trace_set/after"); |
19 | lttv_hooks_add(before, textDump_trace_set_before, NULL); |
20 | lttv_hooks_add(after, textDump_trace_set_after, NULL); |
21 | } |
22 | |
23 | |
24 | void destroy() |
25 | { |
26 | lttv_attributes *a; |
27 | lttv_hooks *before, *after; |
28 | |
29 | a = lttv_global_attributes(); |
30 | before = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, |
31 | "hooks/trace_set/before"); |
32 | after = (lttv_hooks *)lttv_attributes_get_pointer_pathname(a, |
33 | "hooks/trace_set/after"); |
34 | lttv_hooks_remove(before, textDump_trace_set_before, NULL); |
35 | lttv_hooks_remove(after, textDump_trace_set_after, NULL); |
36 | } |
37 | |
38 | /* Insert the hooks before and after each trace and tracefile, and for each |
39 | event. Print a global header. */ |
40 | |
41 | typedef struct _trace_context { |
42 | g_string s; |
43 | FILE *fp; |
44 | bool mandatory_fields; |
45 | lttv_attributes *a; |
46 | } trace_context; |
47 | |
48 | static bool textDump_trace_set_before(void *hook_data, void *call_data) |
49 | { |
50 | FILE *fp; |
51 | int i, j, nb, nbtf; |
52 | lttv_trace_set *s; |
53 | lttv_attributes *a; |
54 | trace_context *c; |
55 | |
56 | a = lttv_global_attributes(); |
57 | s = (lttv_trace_set *)call_data |
58 | |
59 | /* Get the file pointer */ |
60 | |
61 | fp = (FILE *)lttv_attributes_get_pointer_pathname(a, "textDump/file"); |
62 | |
63 | /* For each trace prepare the contexts and insert the hooks */ |
64 | |
65 | nb = lttv_trace_set_number(s); |
66 | for(i = 0 ; i < nb ; i++) { |
67 | c = g_new(trace_context); |
68 | a = lttv_trace_set_trace_attributes(s, i); |
69 | |
70 | if(lttv_attributes_get_pointer_pathname(a, "textDump/context") != NULL) { |
71 | g_error("Recursive call to TextDump"); |
72 | } |
73 | |
74 | c->fp = fp; |
75 | c->mandatory_fields = TRUE; |
76 | c->s = g_string_new(); |
77 | c->a = a; |
78 | |
79 | lttv_attributes_set_pointer_pathname(a, "textDump/context", c); |
80 | |
81 | h = lttv_attributes_get_hooks(a, "hooks/before"); |
82 | lttv_hooks_add(h, textDump_trace_before, c); |
83 | h = lttv_attributes_get_hooks(a, "hooks/after"); |
84 | lttv_hooks_add(h, textDump_trace_after, c); |
85 | h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); |
86 | lttv_hooks_add(h, textDump_tracefile_before, c); |
87 | h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); |
88 | lttv_hooks_add(h, textDump_tracefile_after, c); |
89 | h = lttv_attributes_get_hooks(a, "hooks/event/selected"); |
90 | lttv_hooks_add(h, textDump_event, c); |
91 | } |
92 | |
93 | /* Print the trace set header */ |
94 | fprintf(fp,"Trace set contains %d traces\n\n", nb); |
95 | |
96 | return TRUE; |
97 | } |
98 | |
99 | |
100 | /* Remove the hooks before and after each trace and tracefile, and for each |
101 | event. Print trace set level statistics. */ |
102 | |
103 | static bool textDump_trace_set_after(void *hook_data, void *call_data) |
104 | { |
105 | FILE *fp; |
106 | int i, j, nb, nbtf; |
107 | lttv_trace_set *s; |
108 | lttv_attributes *ga, *a; |
109 | trace_context *c; |
110 | |
111 | ga = lttv_global_attributes(); |
112 | s = (lttv_trace_set *)lttv_attributes_get_pointer_pathname(ga, |
113 | "trace_set/main"); |
114 | |
115 | /* Get the file pointer */ |
116 | |
117 | fp = (FILE *)lttv_attributes_get_pointer_pathname(ga, "textDump/file"); |
118 | |
119 | /* For each trace remove the hooks */ |
120 | |
121 | nb = lttv_trace_set_number(s); |
122 | for(i = 0 ; i < nb ; i++) { |
123 | a = lttv_trace_set_trace_attributes(s, i); |
124 | c = (trace_context *)lttv_attributes_get_pointer_pathname(a, |
125 | "textDump/context"); |
126 | lttv_attributes_set_pointer_pathname(a, "textDump/context", NULL); |
127 | g_string_free(c->s); |
128 | |
129 | h = lttv_attributes_get_hooks(a, "hooks/before"); |
130 | lttv_hooks_remove(h, textDump_trace_before, c); |
131 | h = lttv_attributes_get_hooks(a, "hooks/after"); |
132 | lttv_hooks_remove(h, textDump_trace_after, c); |
133 | h = lttv_attributes_get_hooks(a, "hooks/tacefile/before"); |
134 | lttv_hooks_remove(h, textDump_tracefile_before, c); |
135 | h = lttv_attributes_get_hooks(a, "hooks/tracefile/after"); |
136 | lttv_hooks_remove(h, textDump_tracefile_after, c); |
137 | h = lttv_attributes_get_hooks(a, "hooks/event/selected"); |
138 | lttv_hooks_remove(h, textDump_event, c); |
139 | g_free(c); |
140 | } |
141 | |
142 | /* Print the trace set statistics */ |
143 | |
144 | fprintf(fp,"Trace set contains %d traces\n\n", nb); |
145 | |
146 | print_stats(fp, ga); |
147 | |
148 | return TRUE; |
149 | } |
150 | |
151 | |
152 | /* Print a trace level header */ |
153 | |
154 | static bool textDump_trace_before(void *hook_data, void *call_data) |
155 | { |
156 | ltt_trace *t; |
157 | trace_context *c; |
158 | |
159 | c = (trace_context *)hook_data; |
160 | t = (ltt_trace *)call_data; |
161 | fprintf(c->fp,"Start trace\n"); |
162 | return TRUE; |
163 | } |
164 | |
165 | |
166 | /* Print trace level statistics */ |
167 | |
168 | static bool textDump_trace_after(void *hook_data, void *call_data) |
169 | { |
170 | ltt_trace *t; |
171 | trace_context *c; |
172 | |
173 | c = (trace_context *)hook_data; |
174 | t = (ltt_trace *)call_data; |
175 | fprintf(c->fp,"End trace\n"); |
176 | print_stats(c->fp,c->a); |
177 | return TRUE; |
178 | } |
179 | |
180 | |
181 | static bool textDump_tracefile_before(void *hook_data, void *call_data) |
182 | { |
183 | ltt_tracefile *tf; |
184 | trace_context *c; |
185 | |
186 | c = (trace_context *)hook_data; |
187 | tf = (ltt_tracefile *)call_data; |
188 | fprintf(c->fp,"Start tracefile\n"); |
189 | return TRUE; |
190 | } |
191 | |
192 | |
193 | static bool textDump_tracefile_after(void *hook_data, void *call_data) |
194 | { |
195 | ltt_tracefile *tf; |
196 | trace_context *c; |
197 | |
198 | c = (trace_context *)hook_data; |
199 | tf = (ltt_tracefile *)call_data; |
200 | fprintf(c->fp,"End tracefile\n"); |
201 | return TRUE; |
202 | } |
203 | |
204 | |
205 | /* Print the event content */ |
206 | |
207 | static bool textDump_event(void *hook_data, void *call_data) |
208 | { |
209 | ltt_event *e; |
210 | trace_context *c; |
211 | |
212 | e = (ltt_event *)call_data; |
213 | c = (event_context *)hook_data; |
214 | lttv_event_to_string(e,c->s,c->mandatory_fields); |
215 | fputs(s, c->fd); |
216 | return TRUE; |
217 | } |
218 | |
219 | |
220 | static void print_stats(FILE *fp, lttv_attributes *a) |
221 | { |
222 | int i, j, k, nb, nbc; |
223 | |
224 | lttv_attributes *sa, *ra; |
225 | lttv_attribute *reports, *content; |
226 | lttv_key *key, *previous_key, null_key; |
227 | |
228 | null_key = lttv_key_new_pathname(""); |
229 | sa = (lttv_attributes *)lttv_attributes_get_pointer_pathname(a,"stats"); |
230 | reports = lttv_attributes_array_get(sa); |
231 | nb= lttv_attributes_number(sa); |
232 | |
233 | for(i = 0 ; i < nb ; i++) { |
234 | ra = (lttv_attributes *)reports[i].v.p; |
235 | key = reports[i].key; |
236 | g_assert(reports[i].t == LTTV_POINTER); |
237 | |
238 | /* CHECK maybe have custom handlers registered for some specific reports */ |
239 | |
240 | print_key(fp,key); |
241 | |
242 | content = lttv_attributes_array_get(ra); |
243 | nbc = lttv_attributes_number(ra); |
244 | lttv_attribute_array_sort_lexicographic(content, nbc, NULL, 0); |
245 | previous_key = nullKey; |
246 | for(j = 0 ; j < nbc ; j++) { |
247 | key = content[j].key; |
248 | for(k = 0 ; lttv_key_index(previous_key,k) == lttv_index(key,k) ; k++) |
249 | for(; k < lttv_key_number(key) ; k++) { |
250 | for(l = 0 ; l < k ; l++) fprintf(fp," "); |
251 | fprintf(fp, "%s", lttv_string_id_to_string(lttv_index(key,k))); |
252 | if(k == lttv_key_number(key)) { |
253 | switch(content[j].t) { |
254 | case LTTV_INTEGER: |
255 | fprintf(fp," %d\n", content[j].v.i); |
256 | break; |
257 | case LTTV_TIME: |
258 | fprintf(fp," %d.%09d\n", content[j].v.t.tv_sec, |
259 | content[j].v.t.tv_nsec); |
260 | break; |
261 | case LTTV_DOUBLE: |
262 | fprintf(fp," %g\n", content[j].v.d); |
263 | break; |
264 | case LTTV_POINTER: |
265 | fprintf(fp," pointer\n"); |
266 | break; |
267 | } |
268 | } |
269 | else fprintf(fp,"\n"); |
270 | } |
271 | } |
272 | lttv_attribute_array_destroy(content); |
273 | } |
274 | lttv_attribute_array_destroy(reports); |
275 | lttv_key_destroy(null_key); |
276 | } |
277 | |
278 | |
279 | void lttv_event_to_string(ltt_event *e, lttv_string *s, bool mandatory_fields) |
280 | { |
281 | ltt_facility *facility; |
282 | ltt_eventtype *eventtype; |
283 | ltt_type *type; |
284 | ltt_field *field; |
285 | ltt_time time; |
286 | |
287 | g_string_set_size(s,0); |
288 | |
289 | facility = lttv_event_facility(e); |
290 | eventtype = ltt_event_eventtype(e); |
291 | field = ltt_event_field(e); |
292 | |
293 | if(mandatory_fields) { |
294 | time = ltt_event_time(e); |
295 | g_string_append_printf(s,"%s.%s: %ld.%ld",ltt_facility_name(facility), |
296 | ltt_eventtype_name(eventtype), (long)time.tv_sec, time.tv_nsec); |
297 | } |
298 | |
299 | print_field(e,f,s); |
300 | } |
301 | |
302 | void print_field(ltt_event *e, ltt_field *f, lttv_string *s) { |
303 | ltt_type *type; |
304 | ltt_field *element; |
305 | |
306 | int nb, i; |
307 | |
308 | type = ltt_field_type(f); |
309 | switch(ltt_type_class(type)) { |
310 | case LTT_INT: |
311 | g_string_append_printf(s, " %ld", ltt_event_get_long_int(e,f)); |
312 | break; |
313 | |
314 | case LTT_UINT: |
315 | g_string_append_printf(s, " %lu", ltt_event_get_long_unsigned(e,f)); |
316 | break; |
317 | |
318 | case LTT_FLOAT: |
319 | g_string_append_printf(s, " %g", ltt_event_get_double(e,f)); |
320 | break; |
321 | |
322 | case LTT_STRING: |
323 | g_string_append_printf(s, " \"%s\"", ltt_event_get_string(e,f)); |
324 | break; |
325 | |
326 | case LTT_ENUM: |
327 | g_string_append_printf(s, " %s", ltt_enum_string_get(type, |
328 | event_get_unsigned(e,f)); |
329 | break; |
330 | |
331 | case LTT_ARRAY: |
332 | case LTT_SEQUENCE: |
333 | g_string_append_printf(s, " {"); |
334 | nb = ltt_event_field_element_number(e,f); |
335 | element = ltt_field_element(f); |
336 | for(i = 0 ; i < nb ; i++) { |
337 | ltt_event_field_element_select(e,f,i); |
338 | print_field(e,element,s); |
339 | } |
340 | g_string_append_printf(s, " }"); |
341 | break; |
342 | |
343 | case LTT_STRUCT: |
344 | g_string_append_printf(s, " {"); |
345 | nb = ltt_type_member_number(type); |
346 | for(i = 0 ; i < nb ; i++) { |
347 | element = ltt_field_member(f,i); |
348 | print_field(e,element,s); |
349 | } |
350 | g_string_append_printf(s, " }"); |
351 | break; |
352 | } |
353 | } |
354 | |
355 | |
356 | |
357 | |