1+ import argparse
2+ import sys
3+
4+ supported_keywords = ["$gt" ,"$gte" ,"$lt" ,"$and" ,"$not" ,"$or" ,"$nor" ,"$ne" ,"$eq" ,"$in" ,"$lte" ,"$nin" ,"$exists" ,"$type" ,"$regex" ,"$text" ,"$near" ,"$nearSphere" ,"$size" ,"$natural" ,"$inc" ,"$min" ,"$max" ,
5+ "$rename" ,"$set" ,"$addToSet" ,"$pop" ,"$pull" ,"$push" ,"$pullAll" ,"$each" ,"$position" ,"$sort" ,"$bit" ,"$count" ,"$limit" ,"$match" ,"$skip" ,"$slice" ,"$mod" ,"$geoIntersects" ,
6+ "$geoWithin" ,"$all" ,"$elemMatch" ,"$rand" ,"$mul" ,"$setOnInsert" ,"$abs" ,"$addFields" ,"$bucket" ,"$collStats" ,"$facet" ,"$group" ,"$out" ,"$project" ,"$replaceRoot" ,"$sortByCount" ,
7+ "$unionWith" ,"$unset" ,"$unwind" ,"$add" ,"$arrayElemAt" ,"$arrayToObject" ,"$bottom" ,"$ceil" ,"$cmp" ,"$concatArrays" ,"$concat" ,"$cond" ,"$dateFromString" ,"$dateToString" ,"$divide" ,
8+ "$exp" ,"$filter" ,"$first" ,"$firstN" ,"$floor" ,"$ifNull" ,"$isArray" ,"$isNumber" ,"$last" ,"$let" ,"$literal" ,"$ln" ,"$ltrim" ,"$mergeObjects" ,"$multiply" ,"$objectToArray" ,"$pow" ,
9+ "$reverseArray" ,"$round" ,"$rtrim" ,"$setUnion" ,"$sortArray" ,"$sqrt" ,"$subtract" ,"$top" ,"$toString" ,"$toLower" ,"$toUpper" ,"$trim" ,"$trunc" ,"$zip" ,"$currentDate" ,"$lastN" ,"$reduce" ,
10+ "$strcasecmp" ,"$sql" ,"$stdDevPop" ,"$stdDevSamp" ,"$replaceWith" ,"$sample" ,"$avg" ,"$indexOfArray" ,"$indexOfCP" ,"$log" ,"$log10" ,"$sum" ,"$switch" ,"$toBool" ,"$toDate" ,"$toDouble" ]
11+
12+ not_supported_keywords = ["$expr" ,"$jsonSchema" ,"$box" ,"$center" ,"$centerSphere" ,"$maxDistance" ,"$minDistance" ,"$polygon" ,"$bitsAllClear" ,"$bitsAllSet" ,"$bitsANyClear" ,"$bitsAnySet" ,"$currentData" ,
13+ "$accumulator" ,"$acos" ,"$acosh" ,"$bucketAuto" ,"$changeStream" ,"$currentOp" ,"$densify" ,"$documents" ,"$fill" ,"$geoNear" ,"$graphLookup" ,"$indexStats" ,"$lookup" ,"$merge" ,"$redact" ,
14+ "$search" ,"$searchMeta" ,"$setWindowFields" ,"$allElementsTrue" ,"$anyElementTrue" ,"$asin" ,"$asinh" ,"$atan" ,"$atan2" ,"$atanh" ,"$binarySize" ,"$bottomN" ,
15+ "$bsonSize" ,"$convert" ,"$cosh" ,"$cosh" ,"$covariancePop" ,"$covarianceSamp" ,"$dateAdd" ,"$dateDiff" ,"$dateFromParts" ,"$datesubtract" ,"$dateToParts" ,"$dateTrunc" ,"$dayOfMonth" ,"$dayOfWeek" ,
16+ "$dayOfYear" ,"$degreesToRadians" ,"$denseRank" ,"$derivative" ,"$documentNumber" ,"$expMovingAvg" ,"$function" ,"$getField" ,"$hour" ,"$indexOfBytes" ,"$integral" ,
17+ "$isoDayOfWeek" ,"$isoWeek" ,"$isoWeekYear" ,"$linearFill" ,"$map" ,"$maxN" ,"$meta" ,"$minN" ,"$millisecond" ,"$minute" ,"$month" ,"$radiansToDegrees" ,"$range" ,"$rank" ,"$regexFind" ,
18+ "$regexFindAll" ,"$regexMatch" ,"$replaceOne" ,"$replaceAll" ,"$sampleRate" ,"$second" ,"$setDifference" ,"$setEquals" ,"$setField" ,"$setIntersection" ,"$setIsSubset" ,"$shift" ,"$sin" ,"$sinh" ,
19+ "$split" ,"$stsDevPop" ,"$stsDevSamp" ,"$strLenBytes" ,"$strLenCP" ,"$substr" ,"$substrCP" ,"$tan" ,"$tanh" ,"$toDecimal" ,"$toInt" ,"$toLong" ,
20+ "$toObjectId" ,"$topN" ,"$tsIncrement" ,"$tsSecond" ,"$unsetField" ,"$week" ,"$year" ]
21+
22+ operations = ["\" command\" :{\" find\" " ,"\" command\" :{\" update\" " ,"\" command\" :{\" insert\" " ,"\" command\" :{\" delete\" " ,"\" command\" :{\" aggregate\" " ,"\" command\" :{\" mapReduce\" " ,"\" command\" :{\" getMore\" " ,"\" command\" :{\" findAndModify\" " ]
23+
24+ def main (argv ):
25+ parser = argparse .ArgumentParser ()
26+ parser .add_argument ("--file" ,dest = "file" ,help = "Set the MongoDB log file to analyze" )
27+
28+ argv = parser .parse_args ()
29+
30+ if argv .file is None :
31+ parser .error ("--file is required" )
32+
33+ mongo_log = read_log (argv .file )
34+ supported_dictionary ,not_supported_dictionary ,operation_dictionary = search (mongo_log )
35+ generate_report (supported_dictionary ,not_supported_dictionary ,operation_dictionary )
36+
37+
38+ def read_log (file ):
39+ with open (file , 'r' ) as f :
40+ text = f .readlines ()
41+ return text
42+
43+
44+ def search (input_file ):
45+
46+ supported_dictionary = dict ()
47+ not_supported_dictionary = dict ()
48+ operation_dictionary = dict ()
49+
50+ for line in input_file :
51+ for keyword in supported_keywords :
52+ if keyword in line :
53+ if not keyword in supported_dictionary :
54+ supported_dictionary [keyword ]= 1
55+ else :
56+ supported_dictionary [keyword ]+= 1
57+
58+ for keyword in not_supported_keywords :
59+ if keyword in line :
60+ if not keyword in not_supported_dictionary :
61+ not_supported_dictionary [keyword ]= 1
62+ else :
63+ not_supported_dictionary [keyword ]+= 1
64+
65+ for keyword in operations :
66+ if keyword in line :
67+ if not keyword in operation_dictionary :
68+ operation_dictionary [keyword ]= 1
69+ else :
70+ operation_dictionary [keyword ]+= 1
71+
72+
73+ return supported_dictionary ,not_supported_dictionary ,operation_dictionary
74+
75+
76+
77+
78+ def generate_report (supported_dictionary ,not_supported_dictionary ,operations_dictionary ):
79+
80+ #Calculate aggregation pipelines perc
81+ total = sum (supported_dictionary .values ()) + sum (not_supported_dictionary .values ())
82+ total_supported = sum (supported_dictionary .values ())
83+ total_not_supported = sum (not_supported_dictionary .values ())
84+ if total == 0 :
85+ perc = 0
86+ else :
87+ perc = round (total_supported / total * 100 )
88+
89+ #Calculate operations perc
90+ total_operations = sum (operations_dictionary .values ())
91+
92+ supp_find = operations_dictionary ["\" command\" :{\" find\" " ] if "\" command\" :{\" find\" " in operations_dictionary else 0
93+ supp_delete = operations_dictionary ["\" command\" :{\" delete\" " ] if "\" command\" :{\" delete\" " in operations_dictionary else 0
94+ supp_insert = operations_dictionary ["\" command\" :{\" insert\" " ] if "\" command\" :{\" insert\" " in operations_dictionary else 0
95+ supp_update = operations_dictionary ["\" command\" :{\" update\" " ] if "\" command\" :{\" update\" " in operations_dictionary else 0
96+ supp_findAndModify = operations_dictionary ["\" command\" :{\" findAndModify\" " ] if "\" command\" :{\" findAndModify\" " in operations_dictionary else 0
97+ supp_getMore = operations_dictionary ["\" command\" :{\" getMore\" " ] if "\" command\" :{\" getMore\" " in operations_dictionary else 0
98+
99+ supported_operations = supp_find + supp_delete + supp_insert + supp_update + supp_findAndModify + supp_getMore
100+
101+
102+ if total_operations == 0 :
103+ perc_operations = 0
104+ else :
105+ perc_operations = round (supported_operations / total_operations * 100 )
106+
107+ #Calculate overall compatibility per
108+
109+ if (perc_operations )== 0 :
110+ overall_supported = 0
111+ else :
112+ overall_supported = (perc + perc_operations )/ 2
113+
114+
115+ with open ('report_advisor.txt' ,'w' ) as f :
116+ f .write ("Report Summary for 23ai: " + "\n " )
117+ f .write ("*****************************" + "\n \n \n " )
118+
119+
120+
121+ f .write ("Summary of aggregation operators found: your operators are " + str (perc )+ "% compatible with MongoDB API \n " )
122+ f .write ("****************************************************************************************************" + "\n " )
123+
124+ f .write (" - Total Aggregation Pipelines found: " + str (total )+ "\n " )
125+ f .write (" - Total Supported Aggregation Pipelines: " + str (total_supported )+ "\n " )
126+ f .write (" - Total Not Supported Aggregation Pipelines: " + str (total_not_supported )+ "\n \n \n " )
127+
128+
129+
130+ f .write ("List of supported aggregation operators and the number of times it appears: \n " )
131+ f .write ("********************************************************************************" + "\n " )
132+ f .write (str (supported_dictionary )+ "\n \n \n " )
133+
134+
135+ f .write ("List of NOT supported aggregation operators and the number of times it appears: \n " )
136+ f .write ("********************************************************************************" + "\n " )
137+
138+ f .write (str (not_supported_dictionary )+ "\n \n \n " )
139+
140+ f .write ("Summary of operations found: your operations are " + str (perc_operations )+ "% compatible with MongoDB API \n " )
141+ f .write ("*************************************************************************************" + "\n " )
142+
143+
144+ if '\" command\" :{\" find\" ' in operations_dictionary :
145+ f .write (" - Query operations using find: " + str (operations_dictionary ["\" command\" :{\" find\" " ])+ "\n " )
146+
147+ if '\" command\" :{\" delete\" ' in operations_dictionary :
148+ f .write (" - Delete operations : " + str (operations_dictionary ["\" command\" :{\" delete\" " ])+ "\n " )
149+
150+
151+ if '\" command\" :{\" insert\" ' in operations_dictionary :
152+ f .write (" - Insert operations : " + str (operations_dictionary ["\" command\" :{\" insert\" " ])+ "\n " )
153+
154+ if '\" command\" :{\" update\" ' in operations_dictionary :
155+ f .write (" - Update operations : " + str (operations_dictionary ["\" command\" :{\" update\" " ])+ "\n " )
156+
157+ if '\" command\" :{\" findAndModify\" ' in operations_dictionary :
158+ f .write (" - findAndModify operations : " + str (operations_dictionary ["\" command\" :{\" findAndModify\" " ])+ "\n " )
159+
160+ if '\" command\" :{\" getMore\" ' in operations_dictionary :
161+ f .write (" - getMore operations : " + str (operations_dictionary ["\" command\" :{\" getMore\" " ])+ "\n " )
162+
163+ if "\" command\" :{\" aggregate\" " in operations_dictionary :
164+ f .write (" - Aggregate operations** : " + str (operations_dictionary ["\" command\" :{\" aggregate\" " ])+ "\n " )
165+
166+ if "\" command\" :{\" mapReduce\" " in operations_dictionary :
167+ f .write (" - mapReduce operations** : " + str (operations_dictionary ["\" command\" :{\" mapReduce\" " ])+ "\n " + "\n " + "\n " + "\n " )
168+
169+ f .write ("\n " + "\n " + " ** Operations not supported.\n " )
170+ f .write (" Insert and updates could not be accurate number as appears more in the log." + "\n " + "\n " + "\n " + "\n " )
171+
172+
173+ if __name__ == "__main__" :
174+ main (sys .argv [1 :])
0 commit comments