3
Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com>
4
This file is part of GlusterFS.
6
This file is licensed to you under your choice of the GNU Lesser
7
General Public License, version 3 or any later version (LGPLv3 or
8
later), or the GNU General Public License, version 2 (GPLv2), in all
9
cases as published by the Free Software Foundation.
13
from __future__ import print_function
20
def requestIsEntryOp (self):
22
if op == "CREATE" or op == "LOOKUP" or op == "REMOVE" or op == "LINK" or op == "RENAME" or op == "MKDIR" or op == "RMDIR" or op == "SYMLINK" or op == "MKNOD":
27
def __init__ (self, logline, linecount):
28
self.calllinecount = 0
33
self.replylinecount = 0
39
tokens = logline.strip ().split (" ")
40
self.timestamp = tokens[0] + " " + tokens[1]
41
if "XID:" not in tokens:
44
if "args:" not in tokens:
47
self.calllinecount = linecount
49
xididx = tokens.index ("XID:")
50
self.xid = tokens [xididx+1].strip(",")
52
opidx = tokens.index ("args:")
53
self.op = tokens [opidx-1].strip (":")
54
self.opdata = " ".join(tokens [opidx+1:])
55
if self.requestIsEntryOp ():
56
nameidx = tokens.index ("name:")
57
self.entryname = tokens[nameidx + 1].strip (",")
58
gfididx = tokens.index ("gfid")
59
self.gfid = tokens[gfididx +1].strip(",")
65
def setReply (self, logline, linecount):
66
tokens = logline.strip ().split (" ")
67
timestamp = tokens[0] + " " + tokens[1]
68
statidx = tokens.index ("NFS:")
69
self.replydata = " TimeStamp: " + timestamp + " " + " ".join (tokens [statidx+1:])
70
self.replylinecount = linecount
72
gfididx = tokens.index ("gfid")
73
self.replygfid = tokens [gfididx + 1].strip(",")
76
print("ReqLine: " + str(self.calllinecount) + " TimeStamp: " + self.timestamp + ", XID: " + self.xid + " " + self.op + " ARGS: " + self.opdata + " RepLine: " + str(self.replylinecount) + " " + self.replydata)
80
def __init__ (self, optn, trackfilename, tracknamefh, stats):
82
self.xid_request_map = {}
83
self.orphan_replies = {}
88
self.trackfilename = trackfilename
89
self.tracknamefh = tracknamefh
90
self.trackedfilehandles = []
92
def handle_call_line (self, logline, linecount):
93
newreq = NFSRequest (logline, linecount)
94
xid = newreq.getXID ()
95
if (self.optn == SYNTHESIZE):
96
self.xid_request_map [xid] = newreq
97
self.rqlist.append(newreq)
98
elif self.optn == TRACKFILENAME:
99
if newreq.requestIsEntryOp():
100
if newreq.entryname == self.trackfilename:
101
self.xid_request_map [xid] = newreq
102
self.rqlist.append(newreq)
105
elif self.tracknamefh == ENABLE_TRACKNAME_FH:
106
if len (self.trackedfilehandles) > 0:
107
if newreq.gfid in self.trackedfilehandles:
108
self.xid_request_map [xid] = newreq
109
self.rqlist.append(newreq)
118
def handle_reply_line (self, logline, linecount):
119
tokens = logline.strip ().split (" ")
121
xididx = tokens.index ("XID:")
122
xid = tokens [xididx + 1].strip(",")
123
if xid not in self.xid_request_map.keys ():
124
self.orphan_replies [xid] = logline
126
rq = self.xid_request_map [xid]
127
rq.setReply (logline, linecount)
128
if rq.requestIsEntryOp() and rq.entryname == self.trackfilename:
129
self.trackedfilehandles.append (rq.replygfid)
131
def analyzeLine (self, logline, linecount):
132
tokens = logline.strip ().split (" ")
135
if "XID:" not in tokens:
138
if "args:" in tokens:
140
elif "NFS:" in tokens:
143
if msgtype == self.CALL:
144
self.handle_call_line (logline, linecount)
145
elif msgtype == self.REPLY:
146
self.handle_reply_line (logline, linecount)
151
rcount = len (self.xid_request_map.keys ())
152
orphancount = len (self.orphan_replies.keys ())
153
print("Requests: " + str(rcount) + ", Orphans: " + str(orphancount))
157
for rq in self.rqlist:
162
self.orphan_replies = {}
163
self.xid_request_map = {}
174
ENABLE_TRACKNAME_FH = 1
175
DISABLE_TRACKNAME_FH = 0
179
operation = SYNTHESIZE
181
tracknamefh = DISABLE_TRACKNAME_FH
185
Print the progress of the analysing operations every X number of lines read from
186
the logs, where X is the argument provided to this option.
188
Use this to print a status message every say 10000 lines processed or 100000
189
lines processed to know how much longer the processing will go on for.
192
USAGE: --progress <NUMLINES>
194
if "--progress" in sys.argv:
195
idx = sys.argv.index ("--progress")
196
progmsgcount = int(sys.argv[idx+1])
199
The replies for a NFS request can be separated by hundreds and even thousands
200
of other NFS requests and replies. These can be spread over many hundreds and
201
thousands of log lines. This script maintains a memory dict to map each request
202
to its reply using the XID. Because this is in-core, there is a limit to the
203
number of entries in the dict. At regular intervals, it dumps the mapped
204
requests and the replies into the stdout. The requests whose replies were not
205
found at the point of dumping are left as orphans, i.e. without info about the
206
replies. Use this option to tune the number of lines to maximize the number of
207
requests whose replies are found while balancing the dict size with memory
208
on the machine. The default works fine for most cases.
210
USAGE: --dump <NUMLINES>
212
if "--dump" in sys.argv:
213
idx = sys.argv.index ("--dump")
214
dumpinterval = int(sys.argv[idx+1])
217
The default operation of the script is to output all the requests mapped to
218
their replies in a single line. This operation mode can be changed by this
219
argument. It is used to print only those operations that were performed on the
220
filename given as the argument to this option. Only those entry operations are
221
printed which contain this filename.
223
USAGE: --trackfilename <filename>
225
if "--trackfilename" in sys.argv:
226
idx = sys.argv.index ("--trackfilename")
227
trackfilename = sys.argv[idx + 1]
228
operation = TRACKFILENAME
231
At every dump interval, some stats are printed about the dumped lines.
232
Use this option to disable printing that to avoid cluttering the
235
if "--nostats" in sys.argv:
239
While tracking a file using --trackfilename, we're only given those
240
operations which contain the filename. This excludes a large number
241
of operations which operate on that file using its filehandle instead of
242
the filename. This option enables outputting those operations also. It
243
tracks every single file handle that was ever seen in the log for a given
246
USAGE: --trackfilename
248
if "--tracknamefh" in sys.argv:
249
tracknamefh = ENABLE_TRACKNAME_FH
251
la = NFSLogAnalyzer (operation, trackfilename, tracknamefh, stats)
253
for line in sys.stdin:
254
linecount = linecount + 1
255
if linecount % dumpinterval == 0:
256
sys.stderr.write ("Dumping data..\n")
259
if linecount % progmsgcount == 0:
260
sys.stderr.write ("Integrating line: "+ str(linecount) + "\n")
261
la.analyzeLine (line, linecount)