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