Update FSF address
[lttv.git] / lttv / modules / text / formattedDump.c
CommitLineData
8f07d382
VA
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
b9ce0bad
YB
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
8f07d382
VA
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
50static gboolean a_no_field_names;
51static gboolean a_state;
52static gboolean a_text;
53static gboolean a_strace;
512a7280 54static gboolean a_meta;
ed7dd953
MD
55static char *a_file_name;
56static char *a_format;
8f07d382
VA
57
58static LttvHooks *before_traceset;
59static LttvHooks *event_hook;
60
61static const char default_format[] =
512a7280 62 "channel:%c event:%e timestamp:%t elapsed:%l cpu:%u pid:%d "
beed0826 63 "ppid:%i tgpid:%g process:%p state:%a payload:{ %m }";
8f07d382 64static const char textDump_format[] =
beed0826 65 "%c.%e: %s.%n (%r/%c_%u), %d, %g, %p, %i, %y, %a { %m }";
8f07d382 66static const char strace_format[] = "%e(%m) %s.%n";
512a7280 67static const char *fmt;
8f07d382
VA
68
69static FILE *a_file;
70
71static GString *a_string;
72
512a7280
VA
73static int output_format_len;
74
8f07d382
VA
75static gboolean open_output_file(void *hook_data, void *call_data)
76{
512a7280
VA
77 if (a_text) {
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) */
82 fmt = strace_format;
83 } else if (!a_format) {
84 /* Default format (used if no option) */
85 fmt = default_format;
86 } else {
87 /*
88 * formattedDump format
89 * (used with -F command option following by the desired format)
90 */
91 fmt = a_format;
92 }
93
94 output_format_len = strlen(fmt);
95
8f07d382
VA
96 g_info("Open the output file");
97 if (a_file_name == NULL) {
ed7dd953 98 a_file = stdout;
8f07d382 99 } else {
ed7dd953 100 a_file = fopen(a_file_name, "w");
8f07d382
VA
101 }
102 if (a_file == NULL) {
103 g_error("cannot open file %s", a_file_name);
104 }
105 return FALSE;
106}
107
108static int write_event_content(void *hook_data, void *call_data)
109{
110 gboolean result;
111
112 LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
113
114 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
115
116 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
117
118 LttEvent *e;
119
120 LttvAttributeValue value_filter;
121
122 LttvFilter *filter;
123
124 guint cpu = tfs->cpu;
125 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
126 LttvProcessState *process = ts->running_process[cpu];
127
128 e = ltt_tracefile_get_event(tfc->tf);
129
130 result = lttv_iattribute_find_by_path(attributes, "filter/lttv_filter",
131 LTTV_POINTER, &value_filter);
132 g_assert(result);
133 filter = (LttvFilter *)*(value_filter.v_pointer);
134
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)) {
139 return FALSE;
140 }
141 }
142
512a7280
VA
143 /*
144 * By default, metadata's channel won't be display: it goes directly
1aeb0ff5 145 * to the next event. You can have metadata's information with -M
512a7280
VA
146 * switch (a_meta option).
147 */
148 if (!a_meta && ltt_tracefile_name(tfs->parent.tf) ==
149 g_quark_from_string("metadata")) {
150 return FALSE;
151 /*
152 * TODO:
153 * Investigate the use of filter to do it.
154 */
155 }
156
8f07d382
VA
157 lttv_event_to_string(e, a_string, TRUE, !a_no_field_names, tfs);
158
159 if (a_state) {
160 g_string_append_printf(a_string, "%s ",
161 g_quark_to_string(process->state->s));
162 }
163
164 g_string_append_printf(a_string, "\n");
165
166 fputs(a_string->str, a_file);
167 return FALSE;
168}
169
170void lttv_event_to_string(LttEvent *e, GString *string_buffer, gboolean mandatory_fields,
171 gboolean field_names, LttvTracefileState *tfs)
172{
173 struct marker_field *field;
174 struct marker_info *info;
8f07d382 175
512a7280
VA
176 LttTime time;
177 LttTime elapse;
8f07d382
VA
178 static LttTime time_prev = {0, 0};
179 /*
180 * TODO:
181 * Added this static value into state.c and reset each time you do a
182 * seek for using it in the GUI.
183 */
512a7280 184
8f07d382 185 int i;
8f07d382
VA
186 guint cpu = tfs->cpu;
187 LttvTraceState *ts = (LttvTraceState *)tfs->parent.t_context;
188 LttvProcessState *process = ts->running_process[cpu];
189
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);
196 elapse.tv_sec = 0;
197 elapse.tv_nsec = 0;
198 /*
199 * TODO:
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.
203 */
204 } else {
205 elapse = ltt_time_sub(time, time_prev);
206 time_prev = time;
207 }
208 }
8f07d382
VA
209 g_string_set_size(string_buffer, 0);
210 /*
211 * Switch case:
212 * all '%-' are replaced by the desired value in 'string_buffer'
213 */
512a7280 214 for (i = 0; i < output_format_len; i++) {
8f07d382
VA
215 if (fmt[i] == '%') {
216 switch (fmt[++i]) {
217 case 't':
218 g_string_append_printf(string_buffer,
219 "%ld:%02ld:%02ld.%09ld",
220 time.tv_sec/3600,
221 (time.tv_sec%3600)/60,
222 time.tv_sec%60,
223 time.tv_nsec);
224 break;
225 case 'c':
226 g_string_append(string_buffer,
227 g_quark_to_string(ltt_tracefile_name(tfs->parent.tf)));
228 break;
229 case 'e':
230 g_string_append(string_buffer,
231 g_quark_to_string(info->name));
232 break;
233 case 'd':
234 g_string_append_printf(string_buffer, "%u",
235 process->pid);
236 break;
237 case 's':
238 g_string_append_printf(string_buffer, "%ld",
239 time.tv_sec);
240 break;
241 case 'n':
242 g_string_append_printf(string_buffer, "%ld",
243 time.tv_nsec);
244 break;
245 case 'i':
246 g_string_append_printf(string_buffer, "%u",
247 process->ppid);
248 break;
249 case 'g':
250 g_string_append_printf(string_buffer, "%u",
251 process->tgid);
252 break;
253 case 'p':
254 g_string_append(string_buffer,
255 g_quark_to_string(process->name));
256 break;
8f07d382
VA
257 case 'u':
258 g_string_append_printf(string_buffer, "%u", cpu);
259 break;
260 case 'l':
261 g_string_append_printf(string_buffer,
262 "%ld.%09ld",
263 elapse.tv_sec, elapse.tv_nsec);
264 break;
265 case 'a':
266 g_string_append(string_buffer,
267 g_quark_to_string(process->state->t));
268 break;
269 case 'm':
270 {
271 /*
272 * Get and print markers and tracepoints fields
273 * into 'string_buffer'
274 */
275 if (marker_get_num_fields(info) == 0)
276 break;
277 for (field = marker_get_field(info, 0);
278 field != marker_get_field(info, marker_get_num_fields(info));
279 field++) {
280 if (field != marker_get_field(info, 0)) {
281 g_string_append(string_buffer, ", ");
282 }
283
284 lttv_print_field(e, field, string_buffer, field_names, tfs);
285 }
286 }
287 break;
288 case 'r':
289 g_string_append(string_buffer, g_quark_to_string(
290 ltt_trace_name(ltt_tracefile_get_trace(tfs->parent.tf))));
291 break;
292 case '%':
293 g_string_append_c(string_buffer, '%');
294 break;
295 case 'y':
296 g_string_append_printf(string_buffer,
297 "0x%" PRIx64,
298 process->current_function);
299 break;
300 }
301 } else {
302 /* Copy every character if different of '%' */
303 g_string_append_c(string_buffer, fmt[i]);
304 }
305 }
306}
307
308static void init()
309{
310 gboolean result;
311
312 LttvAttributeValue value;
313
314 LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
315
316 g_info("Init formattedDump.c");
317
318 a_string = g_string_new("");
319
320 a_file_name = NULL;
321 lttv_option_add("output", 'o',
322 "output file where the text is written",
323 "file name",
324 LTTV_OPT_STRING, &a_file_name, NULL, NULL);
325
326 a_text = FALSE;
327 lttv_option_add("text", 'T',
328 "output the textDump format",
329 "",
330 LTTV_OPT_NONE, &a_text, NULL, NULL);
331
332 a_strace = FALSE;
333 lttv_option_add("strace", 'S',
334 "output a \"strace-like\" format",
335 "",
336 LTTV_OPT_NONE, &a_strace, NULL, NULL);
337
512a7280
VA
338 a_meta = FALSE;
339 lttv_option_add("metadata", 'M',
1aeb0ff5 340 "add metadata information",
512a7280
VA
341 "",
342 LTTV_OPT_NONE, &a_meta, NULL, NULL);
343
8f07d382
VA
344 a_format = NULL;
345 lttv_option_add("format", 'F',
346 "output the desired format\n"
347 " FORMAT controls the output. "
348 "Interpreted sequences are:\n"
349 "\n"
350 " %c channel name\n"
351 " %p process name\n"
352 " %e event name\n"
353 " %r path to trace\n"
354 " %t timestamp (e.g., 2:08:54.025684145)\n"
355 " %s seconds\n"
356 " %n nanoseconds\n"
357 " %l elapsed time with the previous event\n"
358 " %d pid\n"
359 " %i ppid\n"
360 " %g tgid\n"
361 " %u cpu\n"
8f07d382
VA
362 " %a state\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);
367
368 result = lttv_iattribute_find_by_path(attributes, "hooks/event",
369 LTTV_POINTER, &value);
370 g_assert(result);
371 event_hook = *(value.v_pointer);
372 g_assert(event_hook);
373 lttv_hooks_add(event_hook, write_event_content, NULL, LTTV_PRIO_DEFAULT);
374
375 result = lttv_iattribute_find_by_path(attributes, "hooks/traceset/before",
376 LTTV_POINTER, &value);
377 g_assert(result);
378 before_traceset = *(value.v_pointer);
379 g_assert(before_traceset);
380 lttv_hooks_add(before_traceset, open_output_file, NULL,
381 LTTV_PRIO_DEFAULT);
382
383}
384
385static void destroy()
386{
387 g_info("Destroy formattedDump");
388
389 lttv_option_remove("format");
390
391 lttv_option_remove("output");
392
393 lttv_option_remove("text");
394
395 lttv_option_remove("strace");
396
512a7280
VA
397 lttv_option_remove("metadata");
398
8f07d382
VA
399 g_string_free(a_string, TRUE);
400
401 lttv_hooks_remove_data(event_hook, write_event_content, NULL);
402
403 lttv_hooks_remove_data(before_traceset, open_output_file, NULL);
404
405}
406
407
408LTTV_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")
This page took 0.040279 seconds and 4 git commands to generate.