]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | # Copyright (C) 2018 Red Hat Inc. |
2 | # | |
3 | # Authors: Sergio Lopez Pascual <slopezpa@redhat.com> | |
4 | # Brad Hubbard <bhubbard@redhat.com> | |
5 | # | |
6 | # This program is free software; you can redistribute it and/or modify | |
7 | # it under the terms of the GNU Library Public License as published by | |
8 | # the Free Software Foundation; either version 2, or (at your option) | |
9 | # any later version. | |
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 Library Public License for more details. | |
15 | # | |
16 | ||
17 | # By default ceph daemons and clients maintain a list of log_max_recent (default | |
18 | # 10000) log entries at a high debug level. This script will attempt to dump out | |
19 | # that log from a ceph::log::Log* passed to the ceph-dump-log function or, if no | |
20 | # object is passed, default to the globally available 'g_ceph_context->_log' | |
21 | # (thanks Kefu). This pointer may be obtained via the _log member of a | |
22 | # CephContext object (i.e. *cct->_log) from any thread that contains such a | |
23 | # CephContext. Normally, you will find a thread waiting in | |
24 | # ceph::logging::Log::entry and the 'this' pointer from such a frame can also be | |
25 | # passed to ceph-dump-log. | |
26 | ||
27 | import gdb | |
28 | from datetime import datetime | |
29 | ||
30 | try: | |
31 | # Python 2 forward compatibility | |
32 | range = xrange | |
33 | except NameError: | |
34 | pass | |
35 | ||
36 | class CephDumpLog(gdb.Command): | |
37 | def __init__(self): | |
38 | super(CephDumpLog, self).__init__( | |
39 | 'ceph-dump-log', | |
40 | gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, False) | |
41 | ||
42 | def invoke(self, args, from_tty): | |
43 | arg_list = gdb.string_to_argv(args) | |
44 | if len(arg_list) < 1: | |
45 | log = gdb.parse_and_eval('g_ceph_context->_log') | |
46 | else: | |
47 | log = gdb.parse_and_eval(arg_list[0]) | |
48 | ||
49 | luminous_mimic = None | |
50 | ||
51 | try: | |
52 | entry = log['m_recent']['m_head'] | |
53 | size = log['m_recent']['m_len'] | |
54 | luminous_mimic = True | |
55 | except gdb.error: | |
56 | entry = log['m_recent']['m_first'] | |
57 | size = log['m_recent']['m_size'] | |
58 | end = log['m_recent']['m_end'] | |
59 | buff = log['m_recent']['m_buff'] | |
60 | ||
61 | for i in range(size): | |
62 | if luminous_mimic: | |
63 | try: # early luminous | |
64 | stamp = int(str(entry['m_stamp']['tv']['tv_sec']) + str(entry['m_stamp']['tv']['tv_nsec'])) | |
65 | logline = entry['m_streambuf']['m_buf'] | |
66 | strlen = int(entry['m_streambuf']['m_buf_len']) | |
67 | except gdb.error: # mimic | |
68 | stamp = entry['m_stamp']['__d']['__r']['count'] | |
69 | pptr = entry['m_data']['m_pptr'] | |
70 | logline = entry['m_data']['m_buf'] | |
71 | strlen = int(pptr - logline) | |
72 | else: | |
73 | stamp = entry['m_stamp']['__d']['__r']['count'] | |
74 | logline = entry['str']['m_holder']['m_start'] | |
75 | strlen = int(entry['str']['m_holder']['m_size']) | |
76 | thread = entry['m_thread'] | |
77 | prio = entry['m_prio'] | |
78 | subsys = entry['m_subsys'] | |
79 | dt = datetime.fromtimestamp(int(stamp) / 1e9) # Giving up some precision | |
80 | gdb.write(dt.strftime('%Y-%m-%d %H:%M:%S.%f ')) | |
81 | gdb.write("thread: {0:#x} priority: {1} subsystem: {2} ". | |
82 | format(int(thread), prio, subsys)) | |
83 | gdb.write(logline.string("ascii", errors='ignore')[0:strlen]) | |
84 | gdb.write("\n") | |
85 | if luminous_mimic: | |
86 | entry = entry['m_next'].dereference() | |
87 | else: | |
88 | entry = entry + 1 | |
89 | if entry >= end: | |
90 | entry = buff | |
91 | ||
92 | CephDumpLog() |