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., 51 Franklin Street, Fifth Floor, 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 state:%a payload:{ %m }";
64 static const char textDump_format
[] =
65 "%c.%e: %s.%n (%r/%c_%u), %d, %g, %p, %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 information 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_printf(string_buffer
, "%u", cpu
);
261 g_string_append_printf(string_buffer
,
263 elapse
.tv_sec
, elapse
.tv_nsec
);
266 g_string_append(string_buffer
,
267 g_quark_to_string(process
->state
->t
));
272 * Get and print markers and tracepoints fields
273 * into 'string_buffer'
275 if (marker_get_num_fields(info
) == 0)
277 for (field
= marker_get_field(info
, 0);
278 field
!= marker_get_field(info
, marker_get_num_fields(info
));
280 if (field
!= marker_get_field(info
, 0)) {
281 g_string_append(string_buffer
, ", ");
284 lttv_print_field(e
, field
, string_buffer
, field_names
, tfs
);
289 g_string_append(string_buffer
, g_quark_to_string(
290 ltt_trace_name(ltt_tracefile_get_trace(tfs
->parent
.tf
))));
293 g_string_append_c(string_buffer
, '%');
296 g_string_append_printf(string_buffer
,
298 process
->current_function
);
302 /* Copy every character if different of '%' */
303 g_string_append_c(string_buffer
, fmt
[i
]);
312 LttvAttributeValue value
;
314 LttvIAttribute
*attributes
= LTTV_IATTRIBUTE(lttv_global_attributes());
316 g_info("Init formattedDump.c");
318 a_string
= g_string_new("");
321 lttv_option_add("output", 'o',
322 "output file where the text is written",
324 LTTV_OPT_STRING
, &a_file_name
, NULL
, NULL
);
327 lttv_option_add("text", 'T',
328 "output the textDump format",
330 LTTV_OPT_NONE
, &a_text
, NULL
, NULL
);
333 lttv_option_add("strace", 'S',
334 "output a \"strace-like\" format",
336 LTTV_OPT_NONE
, &a_strace
, NULL
, NULL
);
339 lttv_option_add("metadata", 'M',
340 "add metadata information",
342 LTTV_OPT_NONE
, &a_meta
, NULL
, NULL
);
345 lttv_option_add("format", 'F',
346 "output the desired format\n"
347 " FORMAT controls the output. "
348 "Interpreted sequences are:\n"
353 " %r path to trace\n"
354 " %t timestamp (e.g., 2:08:54.025684145)\n"
357 " %l elapsed time with the previous event\n"
363 " %y memory address\n"
364 " %m markers and tracepoints fields\n",
365 "format string (e.g., \"channel:%c event:%e process:%p\")",
366 LTTV_OPT_STRING
, &a_format
, NULL
, NULL
);
368 result
= lttv_iattribute_find_by_path(attributes
, "hooks/event",
369 LTTV_POINTER
, &value
);
371 event_hook
= *(value
.v_pointer
);
372 g_assert(event_hook
);
373 lttv_hooks_add(event_hook
, write_event_content
, NULL
, LTTV_PRIO_DEFAULT
);
375 result
= lttv_iattribute_find_by_path(attributes
, "hooks/traceset/before",
376 LTTV_POINTER
, &value
);
378 before_traceset
= *(value
.v_pointer
);
379 g_assert(before_traceset
);
380 lttv_hooks_add(before_traceset
, open_output_file
, NULL
,
385 static void destroy()
387 g_info("Destroy formattedDump");
389 lttv_option_remove("format");
391 lttv_option_remove("output");
393 lttv_option_remove("text");
395 lttv_option_remove("strace");
397 lttv_option_remove("metadata");
399 g_string_free(a_string
, TRUE
);
401 lttv_hooks_remove_data(event_hook
, write_event_content
, NULL
);
403 lttv_hooks_remove_data(before_traceset
, open_output_file
, NULL
);
408 LTTV_MODULE("formattedDump", "Print events with desired format in a file",
409 "Produce a detailed formatted text printout of a trace",
410 init
, destroy
, "batchAnalysis", "option")