Fix erroneous use of "-n" for additional fields, add "-f"
[babeltrace.git] / formats / ctf-text / ctf-text.c
1 /*
2 * BabelTrace - Common Trace Format (CTF)
3 *
4 * CTF Text Format registration.
5 *
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
7 *
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 */
20
21 #include <babeltrace/format.h>
22 #include <babeltrace/ctf-text/types.h>
23 #include <babeltrace/ctf/metadata.h>
24 #include <babeltrace/babeltrace-internal.h>
25 #include <inttypes.h>
26 #include <uuid/uuid.h>
27 #include <sys/mman.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <dirent.h>
33 #include <glib.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36
37 #define NSEC_PER_SEC 1000000000ULL
38
39 int opt_all_field_names,
40 opt_scope_field_names,
41 opt_header_field_names,
42 opt_context_field_names,
43 opt_payload_field_names,
44 opt_all_fields,
45 opt_trace_field,
46 opt_trace_domain_field,
47 opt_trace_procname_field,
48 opt_trace_vpid_field,
49 opt_loglevel_field,
50 opt_delta_field = 1;
51
52 enum field_item {
53 ITEM_SCOPE,
54 ITEM_HEADER,
55 ITEM_CONTEXT,
56 ITEM_PAYLOAD,
57 };
58
59 struct trace_descriptor *ctf_text_open_trace(const char *collection_path,
60 const char *path, int flags,
61 void (*move_pos_slow)(struct ctf_stream_pos *pos, size_t offset,
62 int whence), FILE *metadata_fp);
63 void ctf_text_close_trace(struct trace_descriptor *descriptor);
64
65 static
66 rw_dispatch write_dispatch_table[] = {
67 [ CTF_TYPE_INTEGER ] = ctf_text_integer_write,
68 [ CTF_TYPE_FLOAT ] = ctf_text_float_write,
69 [ CTF_TYPE_ENUM ] = ctf_text_enum_write,
70 [ CTF_TYPE_STRING ] = ctf_text_string_write,
71 [ CTF_TYPE_STRUCT ] = ctf_text_struct_write,
72 [ CTF_TYPE_VARIANT ] = ctf_text_variant_write,
73 [ CTF_TYPE_ARRAY ] = ctf_text_array_write,
74 [ CTF_TYPE_SEQUENCE ] = ctf_text_sequence_write,
75 };
76
77 static
78 struct format ctf_text_format = {
79 .open_trace = ctf_text_open_trace,
80 .close_trace = ctf_text_close_trace,
81 };
82
83 static GQuark Q_STREAM_PACKET_CONTEXT_TIMESTAMP_BEGIN,
84 Q_STREAM_PACKET_CONTEXT_TIMESTAMP_END,
85 Q_STREAM_PACKET_CONTEXT_EVENTS_DISCARDED,
86 Q_STREAM_PACKET_CONTEXT_CONTENT_SIZE,
87 Q_STREAM_PACKET_CONTEXT_PACKET_SIZE;
88
89 static
90 void __attribute__((constructor)) init_quarks(void)
91 {
92 Q_STREAM_PACKET_CONTEXT_TIMESTAMP_BEGIN = g_quark_from_static_string("stream.packet.context.timestamp_begin");
93 Q_STREAM_PACKET_CONTEXT_TIMESTAMP_END = g_quark_from_static_string("stream.packet.context.timestamp_end");
94 Q_STREAM_PACKET_CONTEXT_EVENTS_DISCARDED = g_quark_from_static_string("stream.packet.context.events_discarded");
95 Q_STREAM_PACKET_CONTEXT_CONTENT_SIZE = g_quark_from_static_string("stream.packet.context.content_size");
96 Q_STREAM_PACKET_CONTEXT_PACKET_SIZE = g_quark_from_static_string("stream.packet.context.packet_size");
97 }
98
99 int print_field(struct definition *definition)
100 {
101 /* Print all fields in verbose mode */
102 if (babeltrace_verbose)
103 return 1;
104
105 /* Filter out part of the packet context */
106 if (definition->path == Q_STREAM_PACKET_CONTEXT_TIMESTAMP_BEGIN)
107 return 0;
108 if (definition->path == Q_STREAM_PACKET_CONTEXT_TIMESTAMP_END)
109 return 0;
110 if (definition->path == Q_STREAM_PACKET_CONTEXT_EVENTS_DISCARDED)
111 return 0;
112 if (definition->path == Q_STREAM_PACKET_CONTEXT_CONTENT_SIZE)
113 return 0;
114 if (definition->path == Q_STREAM_PACKET_CONTEXT_PACKET_SIZE)
115 return 0;
116
117 return 1;
118 }
119
120 static
121 void set_field_names_print(struct ctf_text_stream_pos *pos, enum field_item item)
122 {
123 switch (item) {
124 case ITEM_SCOPE:
125 if (opt_all_field_names || opt_scope_field_names)
126 pos->print_names = 1;
127 else
128 pos->print_names = 0;
129 break;
130 case ITEM_HEADER:
131 if (opt_all_field_names || opt_header_field_names)
132 pos->print_names = 1;
133 else
134 pos->print_names = 0;
135 break;
136 case ITEM_CONTEXT:
137 if (opt_all_field_names || opt_context_field_names)
138 pos->print_names = 1;
139 else
140 pos->print_names = 0;
141 break;
142 case ITEM_PAYLOAD:
143 if (opt_all_field_names || opt_payload_field_names)
144 pos->print_names = 1;
145 else
146 pos->print_names = 0;
147
148 break;
149 default:
150 assert(0);
151 }
152 }
153
154 static
155 int ctf_text_write_event(struct stream_pos *ppos,
156 struct ctf_stream *stream)
157 {
158 struct ctf_text_stream_pos *pos =
159 container_of(ppos, struct ctf_text_stream_pos, parent);
160 struct ctf_stream_class *stream_class = stream->stream_class;
161 int field_nr_saved;
162 struct ctf_event *event_class;
163 struct ctf_stream_event *event;
164 uint64_t id;
165 int ret;
166 int dom_print = 0;
167
168 id = stream->event_id;
169
170 if (id >= stream_class->events_by_id->len) {
171 fprintf(stderr, "[error] Event id %" PRIu64 " is outside range.\n", id);
172 return -EINVAL;
173 }
174 event = g_ptr_array_index(stream->events_by_id, id);
175 if (!event) {
176 fprintf(stderr, "[error] Event id %" PRIu64 " is unknown.\n", id);
177 return -EINVAL;
178 }
179 event_class = g_ptr_array_index(stream_class->events_by_id, id);
180 if (!event) {
181 fprintf(stderr, "[error] Event id %" PRIu64 " is unknown.\n", id);
182 return -EINVAL;
183 }
184
185 if (stream->has_timestamp) {
186 uint64_t ts_sec, ts_nsec;
187
188 ts_sec = stream->timestamp / NSEC_PER_SEC;
189 ts_nsec = stream->timestamp % NSEC_PER_SEC;
190 set_field_names_print(pos, ITEM_HEADER);
191 if (pos->print_names)
192 fprintf(pos->fp, "timestamp = ");
193 else
194 fprintf(pos->fp, "[");
195 fprintf(pos->fp, "%3" PRIu64 ".%09" PRIu64,
196 ts_sec, ts_nsec);
197 if (!pos->print_names)
198 fprintf(pos->fp, "]");
199
200 if (pos->print_names)
201 fprintf(pos->fp, ", ");
202 else
203 fprintf(pos->fp, " ");
204 }
205 if ((opt_delta_field || opt_all_fields) && stream->has_timestamp) {
206 uint64_t delta, delta_sec, delta_nsec;
207
208 set_field_names_print(pos, ITEM_HEADER);
209 if (pos->print_names)
210 fprintf(pos->fp, "delta = ");
211 else
212 fprintf(pos->fp, "(");
213 if (pos->last_timestamp != -1ULL) {
214 delta = stream->timestamp - pos->last_timestamp;
215 delta_sec = delta / NSEC_PER_SEC;
216 delta_nsec = delta % NSEC_PER_SEC;
217 fprintf(pos->fp, "+%" PRIu64 ".%09" PRIu64,
218 delta_sec, delta_nsec);
219 } else {
220 fprintf(pos->fp, "+?.?????????");
221 }
222 if (!pos->print_names)
223 fprintf(pos->fp, ")");
224
225 if (pos->print_names)
226 fprintf(pos->fp, ", ");
227 else
228 fprintf(pos->fp, " ");
229 pos->last_timestamp = stream->timestamp;
230 }
231
232 if ((opt_trace_field || opt_all_fields) && stream_class->trace->path[0] != '\0') {
233 set_field_names_print(pos, ITEM_HEADER);
234 if (pos->print_names) {
235 fprintf(pos->fp, "trace = ");
236 }
237 fprintf(pos->fp, "%s", stream_class->trace->path);
238 if (pos->print_names)
239 fprintf(pos->fp, ", ");
240 else
241 fprintf(pos->fp, " ");
242 }
243 if ((opt_trace_domain_field && !opt_all_fields) && stream_class->trace->domain[0] != '\0') {
244 set_field_names_print(pos, ITEM_HEADER);
245 if (pos->print_names) {
246 fprintf(pos->fp, "trace:domain = ");
247 }
248 fprintf(pos->fp, "%s", stream_class->trace->domain);
249 if (pos->print_names)
250 fprintf(pos->fp, ", ");
251 dom_print = 1;
252 }
253 if ((opt_trace_procname_field && !opt_all_fields) && stream_class->trace->procname[0] != '\0') {
254 set_field_names_print(pos, ITEM_HEADER);
255 if (pos->print_names) {
256 fprintf(pos->fp, "trace:procname = ");
257 } else if (dom_print) {
258 fprintf(pos->fp, ":");
259 }
260 fprintf(pos->fp, "%s", stream_class->trace->procname);
261 if (pos->print_names)
262 fprintf(pos->fp, ", ");
263 dom_print = 1;
264 }
265 if ((opt_trace_vpid_field && !opt_all_fields) && stream_class->trace->vpid[0] != '\0') {
266 set_field_names_print(pos, ITEM_HEADER);
267 if (pos->print_names) {
268 fprintf(pos->fp, "trace:vpid = ");
269 } else if (dom_print) {
270 fprintf(pos->fp, ":");
271 }
272 fprintf(pos->fp, "%s", stream_class->trace->vpid);
273 if (pos->print_names)
274 fprintf(pos->fp, ", ");
275 dom_print = 1;
276 }
277 if ((opt_loglevel_field || opt_all_fields) && event_class->loglevel_identifier != 0) {
278 set_field_names_print(pos, ITEM_HEADER);
279 if (pos->print_names) {
280 fprintf(pos->fp, "loglevel = ");
281 } else if (dom_print) {
282 fprintf(pos->fp, ":");
283 }
284 fprintf(pos->fp, "%s (%lld)",
285 g_quark_to_string(event_class->loglevel_identifier),
286 (long long) event_class->loglevel_value);
287 if (pos->print_names)
288 fprintf(pos->fp, ", ");
289 dom_print = 1;
290 }
291 if (dom_print && !pos->print_names)
292 fprintf(pos->fp, " ");
293 set_field_names_print(pos, ITEM_HEADER);
294 if (pos->print_names)
295 fprintf(pos->fp, "name = ");
296 fprintf(pos->fp, "%s", g_quark_to_string(event_class->name));
297 if (pos->print_names)
298 pos->field_nr++;
299 else
300 fprintf(pos->fp, ":");
301
302 /* print cpuid field from packet context */
303 if (stream->stream_packet_context) {
304 if (pos->field_nr++ != 0)
305 fprintf(pos->fp, ",");
306 set_field_names_print(pos, ITEM_SCOPE);
307 if (pos->print_names)
308 fprintf(pos->fp, " stream.packet.context =");
309 field_nr_saved = pos->field_nr;
310 pos->field_nr = 0;
311 set_field_names_print(pos, ITEM_CONTEXT);
312 ret = generic_rw(ppos, &stream->stream_packet_context->p);
313 if (ret)
314 goto error;
315 pos->field_nr = field_nr_saved;
316 }
317
318 /* Only show the event header in verbose mode */
319 if (babeltrace_verbose && stream->stream_event_header) {
320 if (pos->field_nr++ != 0)
321 fprintf(pos->fp, ",");
322 set_field_names_print(pos, ITEM_SCOPE);
323 if (pos->print_names)
324 fprintf(pos->fp, " stream.event.header =");
325 field_nr_saved = pos->field_nr;
326 pos->field_nr = 0;
327 set_field_names_print(pos, ITEM_CONTEXT);
328 ret = generic_rw(ppos, &stream->stream_event_header->p);
329 if (ret)
330 goto error;
331 pos->field_nr = field_nr_saved;
332 }
333
334 /* print stream-declared event context */
335 if (stream->stream_event_context) {
336 if (pos->field_nr++ != 0)
337 fprintf(pos->fp, ",");
338 set_field_names_print(pos, ITEM_SCOPE);
339 if (pos->print_names)
340 fprintf(pos->fp, " stream.event.context =");
341 field_nr_saved = pos->field_nr;
342 pos->field_nr = 0;
343 set_field_names_print(pos, ITEM_CONTEXT);
344 ret = generic_rw(ppos, &stream->stream_event_context->p);
345 if (ret)
346 goto error;
347 pos->field_nr = field_nr_saved;
348 }
349
350 /* print event-declared event context */
351 if (event->event_context) {
352 if (pos->field_nr++ != 0)
353 fprintf(pos->fp, ",");
354 set_field_names_print(pos, ITEM_SCOPE);
355 if (pos->print_names)
356 fprintf(pos->fp, " event.context =");
357 field_nr_saved = pos->field_nr;
358 pos->field_nr = 0;
359 set_field_names_print(pos, ITEM_CONTEXT);
360 ret = generic_rw(ppos, &event->event_context->p);
361 if (ret)
362 goto error;
363 pos->field_nr = field_nr_saved;
364 }
365
366 /* Read and print event payload */
367 if (event->event_fields) {
368 if (pos->field_nr++ != 0)
369 fprintf(pos->fp, ",");
370 set_field_names_print(pos, ITEM_SCOPE);
371 if (pos->print_names)
372 fprintf(pos->fp, " event.fields =");
373 field_nr_saved = pos->field_nr;
374 pos->field_nr = 0;
375 set_field_names_print(pos, ITEM_PAYLOAD);
376 ret = generic_rw(ppos, &event->event_fields->p);
377 if (ret)
378 goto error;
379 pos->field_nr = field_nr_saved;
380 }
381 /* newline */
382 fprintf(pos->fp, "\n");
383 pos->field_nr = 0;
384
385 return 0;
386
387 error:
388 fprintf(stderr, "[error] Unexpected end of stream. Either the trace data stream is corrupted or metadata description does not match data layout.\n");
389 return ret;
390 }
391
392
393 struct trace_descriptor *ctf_text_open_trace(const char *collection_path,
394 const char *path, int flags,
395 void (*move_pos_slow)(struct ctf_stream_pos *pos, size_t offset,
396 int whence), FILE *metadata_fp)
397 {
398 struct ctf_text_stream_pos *pos;
399 FILE *fp;
400
401 pos = g_new0(struct ctf_text_stream_pos, 1);
402
403 pos->last_timestamp = -1ULL;
404 switch (flags & O_ACCMODE) {
405 case O_RDWR:
406 if (!path)
407 fp = stdout;
408 else
409 fp = fopen(path, "w");
410 if (!fp)
411 goto error;
412 pos->fp = fp;
413 pos->parent.rw_table = write_dispatch_table;
414 pos->parent.event_cb = ctf_text_write_event;
415 pos->print_names = 0;
416 break;
417 case O_RDONLY:
418 default:
419 fprintf(stderr, "[error] Incorrect open flags.\n");
420 goto error;
421 }
422
423 return &pos->trace_descriptor;
424 error:
425 g_free(pos);
426 return NULL;
427 }
428
429 void ctf_text_close_trace(struct trace_descriptor *td)
430 {
431 struct ctf_text_stream_pos *pos =
432 container_of(td, struct ctf_text_stream_pos, trace_descriptor);
433 fclose(pos->fp);
434 g_free(pos);
435 }
436
437 void __attribute__((constructor)) ctf_text_init(void)
438 {
439 int ret;
440
441 ctf_text_format.name = g_quark_from_static_string("text");
442 ret = bt_register_format(&ctf_text_format);
443 assert(!ret);
444 }
445
446 /* TODO: finalize */
This page took 0.038625 seconds and 5 git commands to generate.