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

# 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)

Powered by BW's shoe-string budget.