4 * BabelTrace - Convert Text Log to CTF
6 * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * Depends on glibc 2.10 for getline().
21 #include <sys/types.h>
31 #include <uuid/uuid.h>
35 #include <babeltrace/babeltrace.h>
36 #include <babeltrace/ctf/types.h>
38 #define USEC_PER_SEC 1000000UL
41 #define UUID_STR_LEN 37 /* With \0 */
44 int babeltrace_debug
, babeltrace_verbose
;
46 static char *s_outputname
;
47 static int s_timestamp
;
51 /* Metadata format string */
52 static const char metadata_fmt
[] =
53 "typealias integer { size = 8; align = 8; signed = false; } := uint8_t;\n"
54 "typealias integer { size = 32; align = 32; signed = false; } := uint32_t;\n"
57 " major = %u;\n" /* major (e.g. 0) */
58 " minor = %u;\n" /* minor (e.g. 1) */
59 " uuid = \"%s\";\n" /* UUID */
60 " byte_order = %s;\n" /* be or le */
61 " packet.header := struct {\n"
63 " uint8_t uuid[16];\n"
68 " packet.context := struct {\n"
69 " uint32_t content_size;\n"
70 " uint32_t packet_size;\n"
72 "%s" /* Stream event header (opt.) */
77 " fields := struct { string str; };\n"
80 static const char metadata_stream_event_header_timestamp
[] =
81 " typealias integer { size = 64; align = 64; signed = false; } := uint64_t;\n"
82 " event.header := struct {\n"
83 " uint64_t timestamp;\n"
87 void print_metadata(FILE *fp
)
89 char uuid_str
[UUID_STR_LEN
];
91 uuid_unparse(s_uuid
, uuid_str
);
92 fprintf(fp
, metadata_fmt
,
93 BABELTRACE_VERSION_MAJOR
,
94 BABELTRACE_VERSION_MINOR
,
96 BYTE_ORDER
== LITTLE_ENDIAN
? "le" : "be",
97 s_timestamp
? metadata_stream_event_header_timestamp
: "");
101 void write_packet_header(struct ctf_stream_pos
*pos
, uuid_t uuid
)
103 struct ctf_stream_pos dummy
;
106 ctf_dummy_pos(pos
, &dummy
);
107 ctf_align_pos(&dummy
, sizeof(uint32_t) * CHAR_BIT
);
108 ctf_move_pos(&dummy
, sizeof(uint32_t) * CHAR_BIT
);
109 assert(!ctf_pos_packet(&dummy
));
111 ctf_align_pos(pos
, sizeof(uint32_t) * CHAR_BIT
);
112 *(uint32_t *) ctf_get_pos_addr(pos
) = 0xC1FC1FC1;
113 ctf_move_pos(pos
, sizeof(uint32_t) * CHAR_BIT
);
116 ctf_dummy_pos(pos
, &dummy
);
117 ctf_align_pos(&dummy
, sizeof(uint8_t) * CHAR_BIT
);
118 ctf_move_pos(&dummy
, 16 * CHAR_BIT
);
119 assert(!ctf_pos_packet(&dummy
));
121 ctf_align_pos(pos
, sizeof(uint8_t) * CHAR_BIT
);
122 memcpy(ctf_get_pos_addr(pos
), uuid
, 16);
123 ctf_move_pos(pos
, 16 * CHAR_BIT
);
127 void write_packet_context(struct ctf_stream_pos
*pos
)
129 struct ctf_stream_pos dummy
;
132 ctf_dummy_pos(pos
, &dummy
);
133 ctf_align_pos(&dummy
, sizeof(uint32_t) * CHAR_BIT
);
134 ctf_move_pos(&dummy
, sizeof(uint32_t) * CHAR_BIT
);
135 assert(!ctf_pos_packet(&dummy
));
137 ctf_align_pos(pos
, sizeof(uint32_t) * CHAR_BIT
);
138 *(uint32_t *) ctf_get_pos_addr(pos
) = -1U; /* Not known yet */
139 pos
->content_size_loc
= (uint32_t *) ctf_get_pos_addr(pos
);
140 ctf_move_pos(pos
, sizeof(uint32_t) * CHAR_BIT
);
143 ctf_dummy_pos(pos
, &dummy
);
144 ctf_align_pos(&dummy
, sizeof(uint32_t) * CHAR_BIT
);
145 ctf_move_pos(&dummy
, sizeof(uint32_t) * CHAR_BIT
);
146 assert(!ctf_pos_packet(&dummy
));
148 ctf_align_pos(pos
, sizeof(uint32_t) * CHAR_BIT
);
149 *(uint32_t *) ctf_get_pos_addr(pos
) = pos
->packet_size
;
150 ctf_move_pos(pos
, sizeof(uint32_t) * CHAR_BIT
);
154 void write_event_header(struct ctf_stream_pos
*pos
, char *line
,
155 char **tline
, size_t len
, size_t *tlen
,
158 unsigned long sec
, usec
;
164 /* Only need to be executed on first pass (dummy) */
166 /* Extract time from input line */
167 ret
= sscanf(line
, "[%lu.%lu] ", &sec
, &usec
);
169 *tline
= strchr(line
, ']');
172 if ((*tline
)[0] == ' ') {
175 *tlen
= len
+ line
- *tline
;
176 *ts
= (uint64_t) sec
* USEC_PER_SEC
+ (uint64_t) usec
;
180 ctf_align_pos(pos
, sizeof(uint64_t) * CHAR_BIT
);
182 *(uint64_t *) ctf_get_pos_addr(pos
) = *ts
;
183 ctf_move_pos(pos
, sizeof(uint64_t) * CHAR_BIT
);
187 void trace_string(char *line
, struct ctf_stream_pos
*pos
, size_t len
)
189 struct ctf_stream_pos dummy
;
191 char *tline
= line
; /* tline is start of text, after timestamp */
195 printf_debug("read: %s\n", line
);
197 ctf_dummy_pos(pos
, &dummy
);
198 write_event_header(&dummy
, line
, &tline
, len
, &tlen
, &ts
);
199 ctf_align_pos(&dummy
, sizeof(uint8_t) * CHAR_BIT
);
200 ctf_move_pos(&dummy
, tlen
* CHAR_BIT
);
201 if (ctf_pos_packet(&dummy
)) {
202 ctf_pos_pad_packet(pos
);
203 write_packet_header(pos
, s_uuid
);
204 write_packet_context(pos
);
205 if (attempt
++ == 1) {
206 fprintf(stdout
, "[Error] Line too large for packet size (%zukB) (discarded)\n",
207 pos
->packet_size
/ CHAR_BIT
/ 1024);
213 write_event_header(pos
, line
, &tline
, len
, &tlen
, &ts
);
214 ctf_align_pos(pos
, sizeof(uint8_t) * CHAR_BIT
);
215 memcpy(ctf_get_pos_addr(pos
), tline
, tlen
);
216 ctf_move_pos(pos
, tlen
* CHAR_BIT
);
220 void trace_text(FILE *input
, int output
)
222 struct ctf_stream_pos pos
;
224 char *line
= NULL
, *nl
;
227 ctf_init_pos(&pos
, output
, O_RDWR
);
229 write_packet_header(&pos
, s_uuid
);
230 write_packet_context(&pos
);
232 len
= getline(&line
, &linesize
, input
);
235 nl
= strrchr(line
, '\n');
238 trace_string(line
, &pos
, nl
- line
+ 1);
246 fprintf(fp
, "BabelTrace Log Converter %u.%u\n",
247 BABELTRACE_VERSION_MAJOR
,
248 BABELTRACE_VERSION_MINOR
);
250 fprintf(fp
, "Convert for a text log (read from standard input) to CTF.\n");
252 fprintf(fp
, "usage : babeltrace-log [OPTIONS] OUTPUT\n");
254 fprintf(fp
, " OUTPUT Output trace path\n");
256 fprintf(fp
, " -t With timestamps (format: [sec.usec] string\\n)\n");
261 int parse_args(int argc
, char **argv
)
265 for (i
= 1; i
< argc
; i
++) {
266 if (!strcmp(argv
[i
], "-t"))
268 else if (!strcmp(argv
[i
], "-h")) {
271 } else if (argv
[i
][0] == '-')
274 s_outputname
= argv
[i
];
281 int main(int argc
, char **argv
)
283 int fd
, metadata_fd
, ret
;
288 ret
= parse_args(argc
, argv
);
290 fprintf(stdout
, "Error: invalid argument.\n");
300 ret
= mkdir(s_outputname
, S_IRWXU
|S_IRWXG
);
306 dir
= opendir(s_outputname
);
317 fd
= openat(dir_fd
, "datastream", O_RDWR
|O_CREAT
,
318 S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
);
321 goto error_closedirfd
;
324 metadata_fd
= openat(dir_fd
, "metadata", O_RDWR
|O_CREAT
,
325 S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
);
328 goto error_closedatastream
;
330 metadata_fp
= fdopen(metadata_fd
, "w");
333 goto error_closemetadatafd
;
336 uuid_generate(s_uuid
);
337 print_metadata(metadata_fp
);
338 trace_text(stdin
, fd
);
344 error_closemetadatafd
:
345 ret
= close(metadata_fd
);
348 error_closedatastream
:
361 ret
= rmdir(s_outputname
);