You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
6.9 KiB
203 lines
6.9 KiB
# Version 4.0
|
|
import sys,splunk.Intersplunk
|
|
import difflib,time
|
|
import splunk.mining.dcutils as dcu
|
|
|
|
logger = dcu.getLogger()
|
|
|
|
## COMPARE TWO RESULTS
|
|
## ARGS [pos1 pos2] [attribute to compare]
|
|
##
|
|
## DEFAULTS = 1 2 _raw
|
|
##
|
|
|
|
help = """------------------------------------------------------------------------------------
|
|
diff x y compares x to y
|
|
- indicates a line present in x but missing in y
|
|
+ indicates a line present in y but missing in x
|
|
! indicates a line that exists in both x and y, but contains different information
|
|
------------------------------------------------------------------------------------"""
|
|
|
|
contexthelp = """------------------------------------------------------------------------------------
|
|
diff x y compares x to y
|
|
*** a,b **** precedes results from x, lines a through b
|
|
--- a,c ---- precedes results from y, lines a through c
|
|
- indicates a line present in x but missing in y
|
|
+ indicates a line present in y but missing in x
|
|
! indicates a line that exists in both x and y, but contains different information
|
|
------------------------------------------------------------------------------------"""
|
|
|
|
|
|
|
|
|
|
def diff(results, pos1, pos2, attr, showHeader, context, maxlen, diffheader):
|
|
resultcount = len(results)
|
|
|
|
if (pos1 > resultcount):
|
|
return splunk.Intersplunk.generateErrorResults("pos1=%d is out of bounds" % pos1)
|
|
if (pos2 > resultcount):
|
|
return splunk.Intersplunk.generateErrorResults("pos2=%d is out of bounds" % pos2)
|
|
|
|
val1 = results[pos1-1].get(attr, "")
|
|
val2 = results[pos2-1].get(attr, "")
|
|
source1 = results[pos1-1].get("source", "")
|
|
source2 = results[pos2-1].get("source", "")
|
|
outresults = []
|
|
cutoff = False
|
|
if val1.strip() == val2.strip():
|
|
diff = "\n** Results are the Same **\n"
|
|
else:
|
|
if maxlen and (len(val1) > maxlen or len(val2) > maxlen):
|
|
# cut text off at maxlen if nonzero
|
|
val1 = val1[:maxlen]
|
|
val2 = val2[:maxlen]
|
|
|
|
if html:
|
|
htmldiffer = difflib.HtmlDiff()
|
|
diff = htmldiffer.make_file(val1.splitlines(), val2.splitlines())
|
|
|
|
elif context or unified:
|
|
if context:
|
|
differ = difflib.context_diff
|
|
headersize = 3
|
|
else:
|
|
differ = difflib.unified_diff
|
|
headersize = 2
|
|
difflist = list(differ(val1.splitlines(), val2.splitlines(), source1, source2, lineterm=""))
|
|
if not diffheader:
|
|
# trim off +++/--- and such for when the events have no meaningful name
|
|
difflist = difflist[headersize:]
|
|
diff = "\n".join(difflist)
|
|
if showHeader:
|
|
diff = contexthelp + "\n\n" + diff
|
|
else:
|
|
d = difflib.Differ()
|
|
difflist = list(d.compare(val1.splitlines(), val2.splitlines()))
|
|
diff = "\n".join(difflist)
|
|
if showHeader:
|
|
diff = help + "\n\n" + diff
|
|
|
|
result = {}
|
|
# fill in attributes with default values from top result
|
|
for key, otherval in results[pos1-1].items():
|
|
result[key] = otherval
|
|
|
|
# set diff
|
|
result["_raw"] = diff
|
|
result["_decoration"] = "diff"
|
|
result["linecount"] = len(diff.splitlines())
|
|
|
|
outresults.append(result)
|
|
return outresults
|
|
|
|
|
|
results = []
|
|
(isgetinfo, sys.argv) = splunk.Intersplunk.isGetInfo(sys.argv)
|
|
|
|
try:
|
|
html = False
|
|
unified = True
|
|
header = False
|
|
context = False
|
|
attribute = "_raw"
|
|
index1 = 1
|
|
index2 = 2
|
|
maxlen = 100000
|
|
diffheader = False
|
|
|
|
|
|
# poor mans opt
|
|
for a in sys.argv[1:]:
|
|
|
|
# This (old) feature just put a 'help' header for people who don't know
|
|
# how to read diff
|
|
# Commenting out for now since the header has been put into the decorations stuff.
|
|
if a.startswith("header="):
|
|
where = a.find('=')
|
|
value = a[where+1:len(a)]
|
|
if value.startswith('t') or value.startswith("T"):
|
|
header = True
|
|
|
|
elif a.startswith("context="):
|
|
where = a.find('=')
|
|
value = a[where+1:len(a)]
|
|
if value.startswith('t') or value.startswith("T"):
|
|
context = True
|
|
|
|
elif a.startswith("html="):
|
|
where = a.find('=')
|
|
value = a[where+1:len(a)]
|
|
if value.startswith('t') or value.startswith("T"):
|
|
html = True
|
|
|
|
elif a.startswith("unified="):
|
|
where = a.find('=')
|
|
value = a[where+1:len(a)]
|
|
if value.startswith('t') or value.startswith("T"):
|
|
unified = True
|
|
|
|
elif a.startswith("tofile="):
|
|
splunk.Intersplunk.parseError("The 'tofile' argument is no longer supported.")
|
|
# sure would be nice to emit an info message, but our own interfaces
|
|
# are unworkably undocumented. oh well.
|
|
|
|
elif a.startswith("attribute="):
|
|
where = a.find('=')
|
|
attribute = a[where+1:len(a)]
|
|
|
|
elif a.startswith("maxlen="):
|
|
param, value = a.split('=', 1)
|
|
try:
|
|
maxlen = int(value)
|
|
except:
|
|
if isgetinfo:
|
|
splunk.Intersplunk.parseError("Invalid value (%s) for %s. Must be integer quantity of bytes" % (value, param))
|
|
|
|
elif a.startswith("diffheader="):
|
|
param, value = a.split('=', 1)
|
|
if value.lower().startswith('t'):
|
|
diffheader = True
|
|
else:
|
|
diffheader = False
|
|
|
|
elif a.startswith("position1=") or a.startswith("pos1="):
|
|
where = a.find('=')
|
|
try:
|
|
index1 = int(a[where+1:len(a)])
|
|
if (index1 < 1):
|
|
raise ValueError
|
|
except:
|
|
if isgetinfo:
|
|
splunk.Intersplunk.parseError("Invalid value (%s) for %s" % (a[where+1:len(a)],a[:where]))
|
|
|
|
elif a.startswith("position2=") or a.startswith("pos2="):
|
|
where = a.find('=')
|
|
try:
|
|
index2 = int(a[where+1:len(a)])
|
|
if (index2 < 1):
|
|
raise ValueError
|
|
except:
|
|
if isgetinfo:
|
|
splunk.Intersplunk.parseError("Invalid value (%s) for %s" % (a[where+1:len(a)],a[:where]))
|
|
|
|
elif isgetinfo:
|
|
splunk.Intersplunk.parseError("Invalid argument '%s'" % a)
|
|
|
|
if isgetinfo:
|
|
splunk.Intersplunk.outputInfo(False, False, True, False, None, False)
|
|
|
|
results = splunk.Intersplunk.readResults(None, None, False)
|
|
|
|
results = diff(results, index1,index2, attribute, header, context, maxlen, diffheader)
|
|
|
|
except Exception as e:
|
|
import traceback
|
|
stack = traceback.format_exc()
|
|
if isgetinfo:
|
|
splunk.Intersplunk.parseError(str(e))
|
|
|
|
results = splunk.Intersplunk.generateErrorResults(str(e))
|
|
logger.warn("invalid arguments passed to 'diff' search operator. Traceback: %s" % stack)
|
|
|
|
splunk.Intersplunk.outputResults(results)
|