Commit | Line | Data |
---|---|---|
4ed24f86 JD |
1 | # The MIT License (MIT) |
2 | # | |
a3fa57c0 | 3 | # Copyright (C) 2015 - Julien Desfossez <jdesfossez@efficios.com> |
4ed24f86 JD |
4 | # |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | # of this software and associated documentation files (the "Software"), to deal | |
7 | # in the Software without restriction, including without limitation the rights | |
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | # copies of the Software, and to permit persons to whom the Software is | |
10 | # furnished to do so, subject to the following conditions: | |
11 | # | |
12 | # The above copyright notice and this permission notice shall be included in | |
13 | # all copies or substantial portions of the Software. | |
14 | # | |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
21 | # SOFTWARE. | |
22 | ||
bd3cd7c5 JD |
23 | import re |
24 | import time | |
25 | import datetime | |
26 | import socket | |
27 | import struct | |
bd3cd7c5 JD |
28 | |
29 | NSEC_PER_SEC = 1000000000 | |
3f0658cb AB |
30 | NSEC_PER_MSEC = 1000000 |
31 | NSEC_PER_USEC = 1000 | |
32 | ||
33 | BYTES_PER_TIB = 1099511627776 | |
34 | BYTES_PER_GIB = 1073741824 | |
35 | BYTES_PER_MIB = 1048576 | |
36 | BYTES_PER_KIB = 1024 | |
bd3cd7c5 JD |
37 | |
38 | O_CLOEXEC = 0o2000000 | |
39 | ||
40 | ||
baa4cfe9 AB |
41 | def get_syscall_name(event): |
42 | name = event.name | |
43 | ||
44 | if name.startswith('sys_'): | |
fe656dde AB |
45 | # Strip first 4 because sys_ is 4 chars long |
46 | return name[4:] | |
baa4cfe9 AB |
47 | |
48 | # Name begins with syscall_entry_ (14 chars long) | |
fe656dde | 49 | return name[14:] |
baa4cfe9 AB |
50 | |
51 | ||
ced36aab AB |
52 | def is_multi_day_trace_collection(handles): |
53 | time_begin = None | |
54 | ||
55 | for handle in handles.values(): | |
56 | if time_begin is None: | |
57 | time_begin = time.localtime(handle.timestamp_begin / NSEC_PER_SEC) | |
58 | year_begin = time_begin.tm_year | |
59 | month_begin = time_begin.tm_mon | |
60 | day_begin = time_begin.tm_mday | |
61 | ||
62 | time_end = time.localtime(handle.timestamp_end / NSEC_PER_SEC) | |
63 | year_end = time_end.tm_year | |
64 | month_end = time_end.tm_mon | |
65 | day_end = time_end.tm_mday | |
66 | ||
67 | if year_begin != year_end: | |
bd3cd7c5 | 68 | return True |
ced36aab | 69 | elif month_begin != month_end: |
bd3cd7c5 | 70 | return True |
ced36aab | 71 | elif day_begin != day_end: |
bd3cd7c5 | 72 | return True |
ced36aab | 73 | |
bd3cd7c5 JD |
74 | return False |
75 | ||
76 | ||
ced36aab AB |
77 | def trace_collection_date(handles): |
78 | if is_multi_day_trace_collection(handles): | |
bd3cd7c5 | 79 | return None |
ced36aab | 80 | |
652bc6b7 AB |
81 | for handle in handles.values(): |
82 | trace_time = time.localtime(handle.timestamp_begin / NSEC_PER_SEC) | |
83 | year = trace_time.tm_year | |
84 | month = trace_time.tm_mon | |
85 | day = trace_time.tm_mday | |
86 | return (year, month, day) | |
bd3cd7c5 JD |
87 | |
88 | ||
ced36aab | 89 | def extract_timerange(handles, timerange, gmt): |
5b395a93 AB |
90 | pattern = re.compile(r'^\[(?P<begin>.*),(?P<end>.*)\]$') |
91 | if not pattern.match(timerange): | |
20b11dc5 | 92 | return None, None |
5b395a93 AB |
93 | begin_str = pattern.search(timerange).group('begin').strip() |
94 | end_str = pattern.search(timerange).group('end').strip() | |
ced36aab AB |
95 | begin = date_to_epoch_nsec(handles, begin_str, gmt) |
96 | end = date_to_epoch_nsec(handles, end_str, gmt) | |
bd3cd7c5 JD |
97 | return (begin, end) |
98 | ||
99 | ||
ced36aab | 100 | def date_to_epoch_nsec(handles, date, gmt): |
bd3cd7c5 | 101 | # match 2014-12-12 17:29:43.802588035 or 2014-12-12T17:29:43.802588035 |
7cbc1a29 PP |
102 | pattern1 = re.compile(r'^(?P<year>\d{4})-(?P<mon>[01]\d)-' |
103 | r'(?P<day>[0-3]\d)[\sTt]' | |
104 | r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})\.' | |
105 | r'(?P<nsec>\d{9})$') | |
bd3cd7c5 | 106 | # match 2014-12-12 17:29:43 or 2014-12-12T17:29:43 |
7cbc1a29 PP |
107 | pattern2 = re.compile(r'^(?P<year>\d{4})-(?P<mon>[01]\d)-' |
108 | r'(?P<day>[0-3]\d)[\sTt]' | |
109 | r'(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})$') | |
bd3cd7c5 | 110 | # match 17:29:43.802588035 |
7cbc1a29 PP |
111 | pattern3 = re.compile(r'^(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})\.' |
112 | r'(?P<nsec>\d{9})$') | |
bd3cd7c5 | 113 | # match 17:29:43 |
7cbc1a29 | 114 | pattern4 = re.compile(r'^(?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})$') |
5b395a93 | 115 | |
f110718e PP |
116 | # match 93847238974923874 |
117 | pattern5 = re.compile(r'^\d+$') | |
118 | ||
5b395a93 AB |
119 | if pattern1.match(date): |
120 | year = pattern1.search(date).group('year') | |
121 | month = pattern1.search(date).group('mon') | |
122 | day = pattern1.search(date).group('day') | |
123 | hour = pattern1.search(date).group('hour') | |
124 | minute = pattern1.search(date).group('min') | |
125 | sec = pattern1.search(date).group('sec') | |
126 | nsec = pattern1.search(date).group('nsec') | |
127 | elif pattern2.match(date): | |
128 | year = pattern2.search(date).group('year') | |
129 | month = pattern2.search(date).group('mon') | |
130 | day = pattern2.search(date).group('day') | |
131 | hour = pattern2.search(date).group('hour') | |
132 | minute = pattern2.search(date).group('min') | |
133 | sec = pattern2.search(date).group('sec') | |
bd3cd7c5 | 134 | nsec = 0 |
5b395a93 | 135 | elif pattern3.match(date): |
ced36aab AB |
136 | collection_date = trace_collection_date(handles) |
137 | if collection_date is None: | |
bd3cd7c5 JD |
138 | print("Use the format 'yyyy-mm-dd hh:mm:ss[.nnnnnnnnn]' " |
139 | "for multi-day traces") | |
140 | return None | |
ced36aab | 141 | (year, month, day) = collection_date |
5b395a93 AB |
142 | hour = pattern3.search(date).group('hour') |
143 | minute = pattern3.search(date).group('min') | |
144 | sec = pattern3.search(date).group('sec') | |
145 | nsec = pattern3.search(date).group('nsec') | |
146 | elif pattern4.match(date): | |
ced36aab AB |
147 | collection_date = trace_collection_date(handles) |
148 | if collection_date is None: | |
bd3cd7c5 JD |
149 | print("Use the format 'yyyy-mm-dd hh:mm:ss[.nnnnnnnnn]' " |
150 | "for multi-day traces") | |
151 | return None | |
ced36aab | 152 | (year, month, day) = collection_date |
5b395a93 AB |
153 | hour = pattern4.search(date).group('hour') |
154 | minute = pattern4.search(date).group('min') | |
155 | sec = pattern4.search(date).group('sec') | |
bd3cd7c5 | 156 | nsec = 0 |
f110718e PP |
157 | elif pattern5.match(date): |
158 | return int(date) | |
bd3cd7c5 JD |
159 | else: |
160 | return None | |
161 | ||
ced36aab | 162 | date_time = datetime.datetime(int(year), int(month), int(day), int(hour), |
5b395a93 | 163 | int(minute), int(sec)) |
bd3cd7c5 | 164 | if gmt: |
ced36aab AB |
165 | date_time = date_time + datetime.timedelta(seconds=time.timezone) |
166 | return int(date_time.timestamp()) * NSEC_PER_SEC + int(nsec) | |
bd3cd7c5 JD |
167 | |
168 | ||
169 | def ns_to_asctime(ns): | |
170 | return time.asctime(time.localtime(ns/NSEC_PER_SEC)) | |
171 | ||
172 | ||
173 | def ns_to_hour(ns): | |
ced36aab AB |
174 | date = time.localtime(ns / NSEC_PER_SEC) |
175 | return '%02d:%02d:%02d' % (date.tm_hour, date.tm_min, date.tm_sec) | |
bd3cd7c5 JD |
176 | |
177 | ||
178 | def ns_to_hour_nsec(ns, multi_day=False, gmt=False): | |
179 | if gmt: | |
ced36aab | 180 | date = time.gmtime(ns / NSEC_PER_SEC) |
bd3cd7c5 | 181 | else: |
ced36aab | 182 | date = time.localtime(ns / NSEC_PER_SEC) |
bd3cd7c5 | 183 | if multi_day: |
8f2728f2 | 184 | return ('%04d-%02d-%02d %02d:%02d:%02d.%09d' % |
ced36aab AB |
185 | (date.tm_year, date.tm_mon, date.tm_mday, date.tm_hour, |
186 | date.tm_min, date.tm_sec, ns % NSEC_PER_SEC)) | |
bd3cd7c5 | 187 | else: |
8f2728f2 | 188 | return ('%02d:%02d:%02d.%09d' % |
ced36aab | 189 | (date.tm_hour, date.tm_min, date.tm_sec, ns % NSEC_PER_SEC)) |
bd3cd7c5 JD |
190 | |
191 | ||
192 | def ns_to_sec(ns): | |
ced36aab | 193 | return '%lu.%09u' % (ns / NSEC_PER_SEC, ns % NSEC_PER_SEC) |
bd3cd7c5 JD |
194 | |
195 | ||
196 | def ns_to_day(ns): | |
ced36aab AB |
197 | date = time.localtime(ns/NSEC_PER_SEC) |
198 | return '%04d-%02d-%02d' % (date.tm_year, date.tm_mon, date.tm_mday) | |
bd3cd7c5 JD |
199 | |
200 | ||
201 | def sec_to_hour(ns): | |
ced36aab AB |
202 | date = time.localtime(ns) |
203 | return '%02d:%02d:%02d' % (date.tm_hour, date.tm_min, date.tm_sec) | |
bd3cd7c5 JD |
204 | |
205 | ||
206 | def sec_to_nsec(sec): | |
207 | return sec * NSEC_PER_SEC | |
208 | ||
209 | ||
210 | def seq_to_ipv4(ip): | |
3f52a605 | 211 | return '{}.{}.{}.{}'.format(ip[0], ip[1], ip[2], ip[3]) |
bd3cd7c5 JD |
212 | |
213 | ||
214 | def int_to_ipv4(ip): | |
3f52a605 | 215 | return socket.inet_ntoa(struct.pack('!I', ip)) |
bd3cd7c5 JD |
216 | |
217 | ||
3f0658cb AB |
218 | def size_str_to_bytes(size_str): |
219 | try: | |
220 | units_index = next(i for i, c in enumerate(size_str) if c.isalpha()) | |
221 | except StopIteration: | |
222 | # no units found | |
223 | units_index = None | |
224 | ||
225 | if units_index is not None: | |
226 | size = size_str[:units_index] | |
227 | units = size_str[units_index:] | |
228 | else: | |
229 | size = size_str | |
230 | units = None | |
231 | ||
232 | try: | |
233 | size = float(size) | |
234 | except ValueError: | |
235 | raise ValueError('invalid size: {}'.format(size)) | |
236 | ||
237 | # no units defaults to bytes | |
238 | if units is not None: | |
239 | if units in ['t', 'T', 'tB', 'TB']: | |
240 | size *= BYTES_PER_TIB | |
241 | elif units in ['g', 'G', 'gB', 'GB']: | |
242 | size *= BYTES_PER_GIB | |
243 | elif units in ['m', 'M', 'mB', 'MB']: | |
244 | size *= BYTES_PER_MIB | |
245 | elif units in ['k', 'K', 'kB', 'KB']: | |
246 | size *= BYTES_PER_KIB | |
247 | elif units == 'B': | |
248 | # bytes is already the target unit | |
249 | pass | |
250 | else: | |
251 | raise ValueError('unrecognised units: {}'.format(units)) | |
252 | ||
253 | size = int(size) | |
254 | ||
255 | return size | |
256 | ||
257 | ||
258 | def duration_str_to_ns(duration_str): | |
259 | try: | |
260 | units_index = next(i for i, c in enumerate(duration_str) | |
261 | if c.isalpha()) | |
262 | except StopIteration: | |
263 | # no units found | |
264 | units_index = None | |
265 | ||
266 | if units_index is not None: | |
267 | duration = duration_str[:units_index] | |
268 | units = duration_str[units_index:].lower() | |
269 | else: | |
270 | duration = duration_str | |
271 | units = None | |
272 | ||
273 | try: | |
274 | duration = float(duration) | |
275 | except ValueError: | |
276 | raise ValueError('invalid duration: {}'.format(duration)) | |
277 | ||
278 | if units is not None: | |
279 | if units == 's': | |
280 | duration *= NSEC_PER_SEC | |
281 | elif units == 'ms': | |
282 | duration *= NSEC_PER_MSEC | |
283 | elif units in ['us', 'µs']: | |
284 | duration *= NSEC_PER_USEC | |
285 | elif units == 'ns': | |
286 | # ns is already the target unit | |
287 | pass | |
288 | else: | |
289 | raise ValueError('unrecognised units: {}'.format(units)) | |
290 | else: | |
291 | # no units defaults to seconds | |
292 | duration *= NSEC_PER_SEC | |
293 | ||
294 | duration = int(duration) | |
295 | ||
296 | return duration | |
bd3cd7c5 JD |
297 | |
298 | ||
299 | def get_v4_addr_str(ip): | |
300 | # depending on the version of lttng-modules, the v4addr is a | |
301 | # string (< 2.6) or sequence (>= 2.6) | |
302 | try: | |
303 | return seq_to_ipv4(ip) | |
304 | except TypeError: | |
305 | return int_to_ipv4(ip) |