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>
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;
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.
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,
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.
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>
43 #include <ltt/event.h>
44 #include <ltt/trace.h>
50 static gboolean a_no_field_names
;
51 static gboolean a_state
;
52 static gboolean a_text
;
53 static gboolean a_strace
;
54 static gboolean a_meta
;
55 static char *a_file_name
;
56 static char *a_format
;
58 static LttvHooks
*before_traceset
;
59 static LttvHooks
*event_hook
;
61 static const char default_format
[] =
62 "channel:%c event:%e timestamp:%t elapsed:%l cpu:%u pid:%d "
63 "ppid:%i 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 static const char *fmt
;
71 static GString
*a_string
;
73 static int output_format_len
;
75 static gboolean
open_output_file(void *hook_data
, void *call_data
)
78 /* textDump format (used with -T command option) */
79 fmt
= textDump_format
;
80 } else if (a_strace
) {
81 /* strace-like format (used with -S command option) */
83 } else if (!a_format
) {
84 /* Default format (used if no option) */
88 * formattedDump format
89 * (used with -F command option following by the desired format)
94 output_format_len
= strlen(fmt
);
96 g_info("Open the output file");
97 if (a_file_name
== NULL
) {
100 a_file
= fopen(a_file_name
, "w");
102 if (a_file
== NULL
) {
103 g_error("cannot open file %s", a_file_name
);
108 static int write_event_content(void *hook_data
, void *call_data
)
112 LttvIAttribute
*attributes
= LTTV_IATTRIBUTE(lttv_global_attributes());
114 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
116 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
120 LttvAttributeValue value_filter
;
124 guint cpu
= tfs
->cpu
;
125 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
126 LttvProcessState
*process
= ts
->running_process
[cpu
];
128 e
= ltt_tracefile_get_event(tfc
->tf
);
130 result
= lttv_iattribute_find_by_path(attributes
, "filter/lttv_filter",
131 LTTV_POINTER
, &value_filter
);
133 filter
= (LttvFilter
*)*(value_filter
.v_pointer
);
135 /* call to the filter if available */
136 if (filter
->head
!= NULL
) {
137 if (!lttv_filter_tree_parse(filter
->head
, e
, tfc
->tf
,
138 tfc
->t_context
->t
, tfc
, NULL
, NULL
)) {
144 * By default, metadata's channel won't be display: it goes directly
145 * to the next event. You can have metadata's informations with -M
146 * switch (a_meta option).
148 if (!a_meta
&& ltt_tracefile_name(tfs
->parent
.tf
) ==
149 g_quark_from_string("metadata")) {
153 * Investigate the use of filter to do it.
157 lttv_event_to_string(e
, a_string
, TRUE
, !a_no_field_names
, tfs
);
160 g_string_append_printf(a_string
, "%s ",
161 g_quark_to_string(process
->state
->s
));
164 g_string_append_printf(a_string
, "\n");
166 fputs(a_string
->str
, a_file
);
170 void lttv_event_to_string(LttEvent
*e
, GString
*string_buffer
, gboolean mandatory_fields
,
171 gboolean field_names
, LttvTracefileState
*tfs
)
173 struct marker_field
*field
;
174 struct marker_info
*info
;
178 static LttTime time_prev
= {0, 0};
181 * Added this static value into state.c and reset each time you do a
182 * seek for using it in the GUI.
186 guint cpu
= tfs
->cpu
;
187 LttvTraceState
*ts
= (LttvTraceState
*)tfs
->parent
.t_context
;
188 LttvProcessState
*process
= ts
->running_process
[cpu
];
190 info
= marker_get_info_from_id(tfs
->parent
.tf
->mdata
, e
->event_id
);
191 if (mandatory_fields
) {
192 time
= ltt_event_time(e
);
193 /* Calculate elapsed time between current and previous event */
194 if (time_prev
.tv_sec
== 0 && time_prev
.tv_nsec
== 0) {
195 time_prev
= ltt_event_time(e
);
200 * Keep in mind that you should add the ability to
201 * restore the previous event time to state.c if you
202 * want to reuse this code into the GUI.
205 elapse
= ltt_time_sub(time
, time_prev
);
209 g_string_set_size(string_buffer
, 0);
212 * all '%-' are replaced by the desired value in 'string_buffer'
214 for (i
= 0; i
< output_format_len
; i
++) {
218 g_string_append_printf(string_buffer
,
219 "%ld:%02ld:%02ld.%09ld",
221 (time
.tv_sec
%3600)/60,
226 g_string_append(string_buffer
,
227 g_quark_to_string(ltt_tracefile_name(tfs
->parent
.tf
)));
230 g_string_append(string_buffer
,
231 g_quark_to_string(info
->name
));
234 g_string_append_printf(string_buffer
, "%u",
238 g_string_append_printf(string_buffer
, "%ld",
242 g_string_append_printf(string_buffer
, "%ld",
246 g_string_append_printf(string_buffer
, "%u",
250 g_string_append_printf(string_buffer
, "%u",
254 g_string_append(string_buffer
,
255 g_quark_to_string(process
->name
));
258 g_string_append(string_buffer
,
259 g_quark_to_string(process
->brand
));
262 g_string_append_printf(string_buffer
, "%u", cpu
);
265 g_string_append_printf(string_buffer
,
267 elapse
.tv_sec
, elapse
.tv_nsec
);
270 g_string_append(string_buffer
,
271 g_quark_to_string(process
->state
->t
));
276 * Get and print markers and tracepoints fields
277 * into 'string_buffer'
279 if (marker_get_num_fields(info
) == 0)
281 for (field
= marker_get_field(info
, 0);
282 field
!= marker_get_field(info
, marker_get_num_fields(info
));
284 if (field
!= marker_get_field(info
, 0)) {
285 g_string_append(string_buffer
, ", ");
288 lttv_print_field(e
, field
, string_buffer
, field_names
, tfs
);
293 g_string_append(string_buffer
, g_quark_to_string(
294 ltt_trace_name(ltt_tracefile_get_trace(tfs
->parent
.tf
))));
297 g_string_append_c(string_buffer
, '%');
300 g_string_append_printf(string_buffer
,
302 process
->current_function
);
306 /* Copy every character if different of '%' */
307 g_string_append_c(string_buffer
, fmt
[i
]);
316 LttvAttributeValue value
;
318 LttvIAttribute
*attributes
= LTTV_IATTRIBUTE(lttv_global_attributes());
320 g_info("Init formattedDump.c");
322 a_string
= g_string_new("");
325 lttv_option_add("output", 'o',
326 "output file where the text is written",
328 LTTV_OPT_STRING
, &a_file_name
, NULL
, NULL
);
331 lttv_option_add("text", 'T',
332 "output the textDump format",
334 LTTV_OPT_NONE
, &a_text
, NULL
, NULL
);
337 lttv_option_add("strace", 'S',
338 "output a \"strace-like\" format",
340 LTTV_OPT_NONE
, &a_strace
, NULL
, NULL
);
343 lttv_option_add("metadata", 'M',
344 "add metadata informations",
346 LTTV_OPT_NONE
, &a_meta
, NULL
, NULL
);
349 lttv_option_add("format", 'F',
350 "output the desired format\n"
351 " FORMAT controls the output. "
352 "Interpreted sequences are:\n"
357 " %r path to trace\n"
358 " %t timestamp (e.g., 2:08:54.025684145)\n"
361 " %l elapsed time with the previous event\n"
368 " %y memory address\n"
369 " %m markers and tracepoints fields\n",
370 "format string (e.g., \"channel:%c event:%e process:%p\")",
371 LTTV_OPT_STRING
, &a_format
, NULL
, NULL
);
373 result
= lttv_iattribute_find_by_path(attributes
, "hooks/event",
374 LTTV_POINTER
, &value
);
376 event_hook
= *(value
.v_pointer
);
377 g_assert(event_hook
);
378 lttv_hooks_add(event_hook
, write_event_content
, NULL
, LTTV_PRIO_DEFAULT
);
380 result
= lttv_iattribute_find_by_path(attributes
, "hooks/traceset/before",
381 LTTV_POINTER
, &value
);
383 before_traceset
= *(value
.v_pointer
);
384 g_assert(before_traceset
);
385 lttv_hooks_add(before_traceset
, open_output_file
, NULL
,
390 static void destroy()
392 g_info("Destroy formattedDump");
394 lttv_option_remove("format");
396 lttv_option_remove("output");
398 lttv_option_remove("text");
400 lttv_option_remove("strace");
402 lttv_option_remove("metadata");
404 g_string_free(a_string
, TRUE
);
406 lttv_hooks_remove_data(event_hook
, write_event_content
, NULL
);
408 lttv_hooks_remove_data(before_traceset
, open_output_file
, NULL
);
413 LTTV_MODULE("formattedDump", "Print events with desired format in a file",
414 "Produce a detailed formatted text printout of a trace",
415 init
, destroy
, "batchAnalysis", "option")