Add formatted dump module v5
[lttv.git] / lttv / modules / text / formattedDump.c
1 /*
2 * This file is part of the Linux Trace Toolkit viewer
3 * Copyright (C) 2003-2004 Michel Dagenais
4 * 2005 Mathieu Desnoyers
5 * 2011 Vincent Attard <vinc.attard@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License Version 2 as
9 * published by the Free Software Foundation;
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 * MA 02111-1307, USA.
20 */
21
22 /*
23 * Formatted dump plugin prints a formatted output of each events in a trace.
24 * The output format is defined as a parameter. It provides a default format
25 * easy to read, a "strace-like" format and the original textDump format for
26 * backward compatibility.
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include <lttv/lttv.h>
34 #include <lttv/option.h>
35 #include <lttv/module.h>
36 #include <lttv/hook.h>
37 #include <lttv/attribute.h>
38 #include <lttv/iattribute.h>
39 #include <lttv/stats.h>
40 #include <lttv/filter.h>
41 #include <lttv/print.h>
42 #include <ltt/ltt.h>
43 #include <ltt/event.h>
44 #include <ltt/trace.h>
45 #include <stdio.h>
46 #include <inttypes.h>
47 #include <string.h>
48 #include <stdlib.h>
49
50 static gboolean a_no_field_names;
51 static gboolean a_state;
52 static gboolean a_text;
53 static gboolean a_strace;
54
55 static char *a_file_name = NULL;
56 static char *a_format = NULL;
57
58 static LttvHooks *before_traceset;
59 static LttvHooks *event_hook;
60
61 static const char default_format[] =
62 "channel:%c event:%e timestamp:%t elapsed:%l cpu:%u pid:%d ppid:%i "
63 "tgpid:%g process:%p brand:%b state:%a payload:{ %m }";
64 static const char textDump_format[] =
65 "%c.%e: %s.%n (%r/%c_%u), %d, %g, %p, %b, %i, %y, %a { %m }";
66 static const char strace_format[] = "%e(%m) %s.%n";
67
68 static FILE *a_file;
69
70 static GString *a_string;
71
72 static gboolean open_output_file(void *hook_data, void *call_data)
73 {
74 g_info("Open the output file");
75 if (a_file_name == NULL) {
76 a_file = stdout;
77 } else {
78 a_file = fopen(a_file_name, "w");
79 }
80 if (a_file == NULL) {
81 g_error("cannot open file %s", a_file_name);
82 }
83 return FALSE;
84 }
85
86 static int write_event_content(void *hook_data, void *call_data)
87 {
88 gboolean result;
89
90 LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
91
92 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
93
94 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
95
96 LttEvent *e;
97
98 LttvAttributeValue value_filter;
99
100 LttvFilter *filter;
101
102 guint cpu = tfs->cpu;
103 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
104 LttvProcessState *process = ts->running_process[cpu];
105
106 e = ltt_tracefile_get_event(tfc->tf);
107
108 result = lttv_iattribute_find_by_path(attributes, "filter/lttv_filter",
109 LTTV_POINTER, &value_filter);
110 g_assert(result);
111 filter = (LttvFilter *)*(value_filter.v_pointer);
112
113 /* call to the filter if available */
114 if (filter->head != NULL) {
115 if (!lttv_filter_tree_parse(filter->head, e, tfc->tf,
116 tfc->t_context->t, tfc, NULL, NULL)) {
117 return FALSE;
118 }
119 }
120
121 lttv_event_to_string(e, a_string, TRUE, !a_no_field_names, tfs);
122
123 if (a_state) {
124 g_string_append_printf(a_string, "%s ",
125 g_quark_to_string(process->state->s));
126 }
127
128 g_string_append_printf(a_string, "\n");
129
130 fputs(a_string->str, a_file);
131 return FALSE;
132 }
133
134 void lttv_event_to_string(LttEvent *e, GString *string_buffer, gboolean mandatory_fields,
135 gboolean field_names, LttvTracefileState *tfs)
136 {
137 struct marker_field *field;
138 struct marker_info *info;
139 LttTime time;
140
141 static LttTime time_prev = {0, 0};
142 /*
143 * TODO:
144 * Added this static value into state.c and reset each time you do a
145 * seek for using it in the GUI.
146 */
147 LttTime elapse;
148 const char *fmt;
149 int i;
150 int len;
151 guint cpu = tfs->cpu;
152 LttvTraceState *ts = (LttvTraceState *)tfs->parent.t_context;
153 LttvProcessState *process = ts->running_process[cpu];
154
155 info = marker_get_info_from_id(tfs->parent.tf->mdata, e->event_id);
156 if (mandatory_fields) {
157 time = ltt_event_time(e);
158 /* Calculate elapsed time between current and previous event */
159 if (time_prev.tv_sec == 0 && time_prev.tv_nsec == 0) {
160 time_prev = ltt_event_time(e);
161 elapse.tv_sec = 0;
162 elapse.tv_nsec = 0;
163 /*
164 * TODO:
165 * Keep in mind that you should add the ability to
166 * restore the previous event time to state.c if you
167 * want to reuse this code into the GUI.
168 */
169 } else {
170 elapse = ltt_time_sub(time, time_prev);
171 time_prev = time;
172 }
173 }
174 if (a_text) {
175 /* textDump format (used with -T command option) */
176 fmt = textDump_format;
177 } else if (a_strace) {
178 /* strace-like format (used with -S command option) */
179 fmt = strace_format;
180 } else if (!a_format) {
181 /* Default format (used if no option) */
182 fmt = default_format;
183 } else {
184 /*
185 * formattedDump format
186 * (used with -F command option following by the desired format)
187 */
188 fmt = a_format;
189 }
190
191 g_string_set_size(string_buffer, 0);
192 /*
193 * Switch case:
194 * all '%-' are replaced by the desired value in 'string_buffer'
195 */
196 len = strlen(fmt);
197 for (i = 0; i < len; i++) {
198 if (fmt[i] == '%') {
199 switch (fmt[++i]) {
200 case 't':
201 g_string_append_printf(string_buffer,
202 "%ld:%02ld:%02ld.%09ld",
203 time.tv_sec/3600,
204 (time.tv_sec%3600)/60,
205 time.tv_sec%60,
206 time.tv_nsec);
207 break;
208 case 'c':
209 g_string_append(string_buffer,
210 g_quark_to_string(ltt_tracefile_name(tfs->parent.tf)));
211 break;
212 case 'e':
213 g_string_append(string_buffer,
214 g_quark_to_string(info->name));
215 break;
216 case 'd':
217 g_string_append_printf(string_buffer, "%u",
218 process->pid);
219 break;
220 case 's':
221 g_string_append_printf(string_buffer, "%ld",
222 time.tv_sec);
223 break;
224 case 'n':
225 g_string_append_printf(string_buffer, "%ld",
226 time.tv_nsec);
227 break;
228 case 'i':
229 g_string_append_printf(string_buffer, "%u",
230 process->ppid);
231 break;
232 case 'g':
233 g_string_append_printf(string_buffer, "%u",
234 process->tgid);
235 break;
236 case 'p':
237 g_string_append(string_buffer,
238 g_quark_to_string(process->name));
239 break;
240 case 'b':
241 g_string_append_printf(string_buffer, "%u",
242 process->brand);
243 break;
244 case 'u':
245 g_string_append_printf(string_buffer, "%u", cpu);
246 break;
247 case 'l':
248 g_string_append_printf(string_buffer,
249 "%ld.%09ld",
250 elapse.tv_sec, elapse.tv_nsec);
251 break;
252 case 'a':
253 g_string_append(string_buffer,
254 g_quark_to_string(process->state->t));
255 break;
256 case 'm':
257 {
258 /*
259 * Get and print markers and tracepoints fields
260 * into 'string_buffer'
261 */
262 if (marker_get_num_fields(info) == 0)
263 break;
264 for (field = marker_get_field(info, 0);
265 field != marker_get_field(info, marker_get_num_fields(info));
266 field++) {
267 if (field != marker_get_field(info, 0)) {
268 g_string_append(string_buffer, ", ");
269 }
270
271 lttv_print_field(e, field, string_buffer, field_names, tfs);
272 }
273 }
274 break;
275 case 'r':
276 g_string_append(string_buffer, g_quark_to_string(
277 ltt_trace_name(ltt_tracefile_get_trace(tfs->parent.tf))));
278 break;
279 case '%':
280 g_string_append_c(string_buffer, '%');
281 break;
282 case 'y':
283 g_string_append_printf(string_buffer,
284 "0x%" PRIx64,
285 process->current_function);
286 break;
287 }
288 } else {
289 /* Copy every character if different of '%' */
290 g_string_append_c(string_buffer, fmt[i]);
291 }
292 }
293 }
294
295 static void init()
296 {
297 gboolean result;
298
299 LttvAttributeValue value;
300
301 LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
302
303 g_info("Init formattedDump.c");
304
305 a_string = g_string_new("");
306
307 a_file_name = NULL;
308 lttv_option_add("output", 'o',
309 "output file where the text is written",
310 "file name",
311 LTTV_OPT_STRING, &a_file_name, NULL, NULL);
312
313 a_text = FALSE;
314 lttv_option_add("text", 'T',
315 "output the textDump format",
316 "",
317 LTTV_OPT_NONE, &a_text, NULL, NULL);
318
319 a_strace = FALSE;
320 lttv_option_add("strace", 'S',
321 "output a \"strace-like\" format",
322 "",
323 LTTV_OPT_NONE, &a_strace, NULL, NULL);
324
325 a_format = NULL;
326 lttv_option_add("format", 'F',
327 "output the desired format\n"
328 " FORMAT controls the output. "
329 "Interpreted sequences are:\n"
330 "\n"
331 " %c channel name\n"
332 " %p process name\n"
333 " %e event name\n"
334 " %r path to trace\n"
335 " %t timestamp (e.g., 2:08:54.025684145)\n"
336 " %s seconds\n"
337 " %n nanoseconds\n"
338 " %l elapsed time with the previous event\n"
339 " %d pid\n"
340 " %i ppid\n"
341 " %g tgid\n"
342 " %u cpu\n"
343 " %b brand\n"
344 " %a state\n"
345 " %y memory address\n"
346 " %m markers and tracepoints fields\n",
347 "format string (e.g., \"channel:%c event:%e process:%p\")",
348 LTTV_OPT_STRING, &a_format, NULL, NULL);
349
350 result = lttv_iattribute_find_by_path(attributes, "hooks/event",
351 LTTV_POINTER, &value);
352 g_assert(result);
353 event_hook = *(value.v_pointer);
354 g_assert(event_hook);
355 lttv_hooks_add(event_hook, write_event_content, NULL, LTTV_PRIO_DEFAULT);
356
357 result = lttv_iattribute_find_by_path(attributes, "hooks/traceset/before",
358 LTTV_POINTER, &value);
359 g_assert(result);
360 before_traceset = *(value.v_pointer);
361 g_assert(before_traceset);
362 lttv_hooks_add(before_traceset, open_output_file, NULL,
363 LTTV_PRIO_DEFAULT);
364
365 }
366
367 static void destroy()
368 {
369 g_info("Destroy formattedDump");
370
371 lttv_option_remove("format");
372
373 lttv_option_remove("output");
374
375 lttv_option_remove("text");
376
377 lttv_option_remove("strace");
378
379 g_string_free(a_string, TRUE);
380
381 lttv_hooks_remove_data(event_hook, write_event_content, NULL);
382
383 lttv_hooks_remove_data(before_traceset, open_output_file, NULL);
384
385 }
386
387
388 LTTV_MODULE("formattedDump", "Print events with desired format in a file",
389 "Produce a detailed formatted text printout of a trace",
390 init, destroy, "batchAnalysis", "option")
This page took 0.036987 seconds and 4 git commands to generate.