-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathklgrep.py v3
456 lines (385 loc) · 18.9 KB
/
klgrep.py v3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#indique l'encodage à utiliser
#the first line in my python file is the adress where python is redirecting for run my script
#without to type python ^^
#the command to redirect the python path is
#export PATH="/usr/bin/env:/home/ljcharles/klgrep:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/bin/python"
#Le python path indique à python quels dossiers il doit prendre en compte pour sa recherche de modules.
#open .bash_profile ouvre le profile bash pour ajouter de manière permanente ma direction au pythonpath
#pour donner des doits d'éxécution au fichier on tape chmod +x klgrep.py
#pwd pour obtenir le répertoir courant
#cd pour se déplacer
#ctrl+c pour sortir ou ctrl+q si wtf
#history pour l'historique des commandes, !789 pour activer la command 789, ctrl + r raccourci reverse-history
##############################
# Recherche un terme au #
# sein d’un fichier de log #
# avec options et #
# affiche les « tranches » #
# de log contenant ce terme. #
# ------------------------- #
# Créé : le 11/05/2015 #
# Auteur : Freshloic #
# Tuteur : Mr BYRAM Miguel #
##############################
#importer des modules
import sys, re, logging, os.path, getopt
from logging.handlers import RotatingFileHandler
# création de l'objet logger qui va nous servir à écrire dans les logs
logger = logging.getLogger()
# on met le niveau du logger à DEBUG, comme ça il écrit tout
logger.setLevel(logging.DEBUG)
# création d'un formateur qui va ajouter le temps, le niveau
# de chaque message quand on écrira un message dans le log
formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
# création d'un handler qui va rediriger une écriture du log vers
# un fichier en mode 'append', avec 1 backup et une taille max de 1Mo
file_handler = RotatingFileHandler('activity.log', 'a', 1000000, 1)
# on lui met le niveau sur DEBUG, on lui dit qu'il doit utiliser le formateur
# créé précédement et on ajoute ce handler au logger
# file_handler.setLevel(logging.DEBUG)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# création d'un second handler qui va rediriger chaque écriture de log
# sur la console
stream_handler = logging.StreamHandler()
# affiche que les messages >=WARN
stream_handler.setLevel(logging.WARN)
logger.addHandler(stream_handler)
logger.debug("%%% DEBUT %%%");
"""
klgrep.py works the same way classic grep does (tho much more
simplified and with less functionality) but provides all the regular
expression patterns available in Python.
procédure à lancer
début: recherche term2find au sein de file2lookinto
fin: affiche les tranches de log contenant term2find
"""
#fonction help avec helpcomplete et helpreduite
def help():
if helpcomplete:
helpguideoptions = """Usage: klgrep.py [-h] [-m {nbrmax}] [-c] [-n] [-d] [-E] [-i] [-H] [-v] [-q] {TERME} {FICHIER}
Recherche un terme au sein d’un fichier de log et affiche les « tranches » de log contenant ce terme.
Exemple: klgrep.py -c "bscsresponder" "journal.log"
Sélection et interprétation de l'expression régulière:
-E, --regex utiliser le TERME comme expression régulière
-q, --quiet n'affiche rien retourne seulement le code retour:
- 0 s'il a trouvé une tranche contenant l'occurence
- 1 sinon
-i, --ignore-case ignorer la distinction de la casse
Divers:
-v, --verbose afficher des informations de débogage:
* mode verbeux (level debug)
-d, --debug afficher des informations de débogage:
* mode debug (level warning)
-h, --help afficher l'aide et quitter
Contrôle de sortie:
-m nbrmax, --max-count=nbrmax arrêter après nbrmaxtranche concordances
du TERME rechercher
-H, --Highlight afficher le TERME en couleur
-n, --numlines afficher les numéros des lignes dans
toutes les tranches
-c, --counttranches afficher seulement le nombre de tranches
contenant le TERME recherché"""
print (helpguideoptions) #on affiche helpguideoptions...
else:#si on souhaite avoir l'aide réduite
helpreduite = """Usage: klgrep.py [-h] [-m {nbrmax}] [-c] [-n] [-d] [-E] [-i] [-H] [-v] [-q] {TERME} {FICHIER}
Recherche un terme au sein d’un fichier de log et affiche les « tranches » de log contenant ce terme.
Exemple: klgrep.py -c "bscsresponder" "journal.log"
"Pour en savoir davantage, faites: « klgrep.py --help »." """
print helpreduite #on affiche helpreduite...
#...et on quitte
sortie_propre(2)
#fonction analyse_commande qui analyse les termes passer en arguments lors du lancement du programme
def analyse_commande(argv):
#We can use a global variable in other functions by declaring it as global in each function that assigns to it
global regexopt
global verbose
global investigation
global helpcomplete
global maxcountopt
global maxcount
global isobject
global counttranches
global ignorecase
global coloropt
global modesilencieux
global nbrtanche
global file2lookinto
global term2find
global nbrlinesopt
# we give default values to variables
nbrtanche = 0
#we try tableau_options = hm:cEivq and tableau_arguments = argv
try:
tableau_options, tableau_arguments = getopt.getopt(argv, "hm:cdnEiHvq", ["help", "max-count=", "counttranches", "debug", "numlines", "regex", "ignore-case", "Highlight", "verbose", "quiet"])
#on intercepte l'erreur relative aux options
except getopt.GetoptError, err:
# else print help information and exit:
logger.error("klgrep: option invalide --" + str(err)) # will print something like "option -a not recognized"
helpcomplete = False
help()
sortie_propre(2)
# pour chaque options et valeur dans nom_option
for nom_option, valeur in tableau_options:
#si l'option est verbose
if nom_option in ("-v", "--verbose"):
verbose = True
logger.debug("verbeux= " + str(verbose))
stream_handler.setLevel(logging.DEBUG)
#si l'option est debug
elif nom_option in ("-d", "--debug"):
investigation = True
if investigation:
logger.debug("debug= " + str(investigation))
logger.setLevel(logging.DEBUG)
#sinon si l'option est help
elif nom_option in ("-h", "--help"):
helpcomplete = True
help()
sortie_propre(2)
elif nom_option in ("-m", "--max-count"): #sinon si l'option est maxcount
maxcountopt = True
logger.debug("maxcountopt = " + str(maxcountopt))
try:
valeur=int(valeur)
except ValueError:
logger.warning("l'option m ou max-count doit être suivie d'un nombre entier positif, '"+str(valeur)+"' ne l'est pas!")
helpcomplete = False
help()
sortie_propre(2)
if valeur > 0:
logger.debug("valeur_maxcount = "+str(valeur))
maxcount = valeur #valeur est obligatoirement un nombre entier positif
elif valeur == 0:
logger.warning("Si maxcount = 0 rien ne sera affiché");
else:#si la valeur est négative on affiche un message d'erreur
logger.warning("l'option m ou max-count doit être suivie d'un nombre entier positif, '"+str(valeur)+"' ne l'est pas!")
helpcomplete = False
help()
sortie_propre(2)
elif nom_option in ("-i", "--ignore-case"): #sinon si l'option est d'ignorer la majuscule ou la minuscule
ignorecase=True
logger.debug("ignorecase = " + str(ignorecase))
elif nom_option in ("-n", "--numlines"): #sinon si l'option est d'ajouter les numéros de lignes
nbrlinesopt=True
logger.debug("numlines = " + str(nbrlinesopt))
elif nom_option in ("-H", "--Highlight"): #sinon si l'option est d'ignorer la majuscule ou la minuscule
coloropt=True
logger.debug("coloropt = " + str(coloropt))
elif nom_option in ("-E", "--regex"): #sinon si l'option est regex on cherchera term2find comme une expression régulière
regexopt = True
logger.debug("regexopt = " + str(regexopt))
elif nom_option in ("-c", "--count"): #sinon si l'option est count
counttranches = True
logger.debug("counttranches = " + str(counttranches))
elif nom_option in ("-q", "--quiet"): #on cherche si il y a des tranches
modesilencieux = True
logger.debug("modesilencieux = " + str(modesilencieux))
else: #Sinon option n'est pas gérée
logger.error("Option non gérée (%s)", nom_option)
helpcomplete = False
help()
sortie_propre(2)
if not investigation:
logger.setLevel(logging.WARN)
logger.addHandler(stream_handler)
try:
term2find = tableau_arguments[0] #we recover term2find dans les argumments donnés par les utilisateurs
except:
logger.error("Vous avez oublié d'entrer le TERME à rechercher")
helpcomplete = False
help()
sortie_propre(2)
try:
file2lookinto = tableau_arguments[1] #we recover file2lookinto dans les argumments donnés par les utilisateurs
except:
logger.error("Vous avez oublié d'entrer le le nom du fichier")
helpcomplete = False
help()
sortie_propre(2)
#recherche le terme à trouver dans la tranche et le retourne en couleur
def color(term2find, tranche):
BEGIN_COLOR="\033[1;33m"#début couleur du terme recherché (ici jaune)
END_COLOR="\033[m"#fin couleur du terme recherché, le texte suivant aura sa couleur d'origine
result = ""
mot = r"^(.*?)(" + term2find + ")(.*)$(?ms)"
if regexopt:
if ignorecase:
mot = r"^(.*?)(" + term2find + ")(.*)$(?msi)"
#le i dans msi permet d'ignorer la casse, le ms permet une recherche sur chaque ligne d'un texte
ismot = re.search(mot, str(tranche))
else:#on a une regex pour rechercher et on ne prends pas en compte la casse
mot = r"^(.*?)(" + term2find + ")(.*)$(?ms)"
ismot = re.search(mot, str(tranche))
else:#on n'a pas de regex
if ignorecase:
noregterm=re.escape(term2find)
mot = r"^(.*?)(" + noregterm + ")(.*)$(?msi)"
ismot = re.search(mot, str(tranche))
# on n'a pas de regex pour rechercher et on ne prends pas en compte la casse
# re.escape(string) Return string with all non-alphanumerics backslashed;
# this is useful if you want to match an arbitrary literal string
# that may have regular expression metacharacters in it
else:
noregterm=re.escape(term2find)
mot = r"^(.*?)(" + noregterm + ")(.*)$(?ms)"
ismot = re.search(mot,str(tranche))
while ismot: #tant que l'on recherche le mot dans la tranche
result+= ismot.group(1) + BEGIN_COLOR + ismot.group(2) + END_COLOR
#result = result + la tranche partager en 2 groupes (début de tranche + plus terme trouvé)
tranche = str(ismot.group(3)) #tranche vaut alors le groupe 3
ismot = re.search(mot,tranche)# on recherche le mot dans le groupe 3
return result+tranche #on retourne le résultat plus la tranche ne contenant pas le terme
#maxcountfunct permet d'afficher le nombre (positif) de tranche voulu par l'utilisateur
def maxcountfunct():
if maxcountopt:
if coloropt:
if countranche < (maxcount+1): #tant que countranche est inf à maxcount qui reprend l'argument...
sys.stdout.write (str(color(term2find,tranche)))#sys.stdout.write permet d'écrire sans retour à la ligne
else:#si on a pas l'option couleur
if countranche < (maxcount+1): #tant que countranche est inf à maxcount qui reprend l'argument...
sys.stdout.write (str(tranche))
sortie_propre(0)
"""
procédure à lancer
début: recherche term2find au sein de file2lookinto
fin: affiche les tranches de log contenant term2find
"""
def searchinfile(term2find,file2lookinto):
#gérer une exception
try:
#la variable file est égale à l'ouverture du fichier
file = open(file2lookinto, "r")
#tranche is undefined
global tranche
global countranche
global coloropt
tranche = ""
nbrtranche = 0
nbrlines = 0
#si la taille du fichier is equals to zero so print the file is empty
if os.path.getsize(file2lookinto) == 0:
logging.error("Le fichier est vide")
sortie_propre(2)
#Tant qu'il y a des lignes dans le fichier
while 1 :
line = file.readline()
nbrlines += 1
#not line = plus de lignes alors pause
if not line:
break
#regular expression de la date
regexdate = r"^\d{4}\-\d{2}-\d{2}"
#recherche de la date
isdate = re.search(regexdate,str(line))
#si on trouve une date dans le texte au début d'une ligne
if isdate:
""""on affiche la tranche et la ligne de séparation
\n permet d'aller à la ligne
On écrase la tranche par la ligne
c'est a dire là tranche = date"""
if regexopt:
if ignorecase:
mot = r"^(.*)(" + term2find + ")(.*)$(?msi)"
#le i dans msi permet d'ignorer la casse, le ms permet une recherche sur chaque ligne d'un texte
isobject = re.search(mot,str(tranche))
else: #sinon on recherche une regex en ne prenant pas en compte la casse
isobject = re.search(term2find,str(tranche))
else: #si on n'utilise pas d'expression regulière = regex
if ignorecase:
isobject = term2find.lower() in tranche.lower()
else: #sinon on recherche term2find en prenant en compte la casse
isobject = term2find in tranche
if isobject:
nbrtranche += 1
countranche += 1
if modesilencieux or counttranches:
affiche = "vide" #ne pas effacer sinon bug xD, permet de ne rien afficher
elif maxcountopt:#sinon si on a l'option maxcount
print '\033[1;33m----------------------------------------\033[1;m'
maxcountfunct()
else:#si on aucune de ces options
print '\033[1;33m----------------------------------------\033[1;m'
if coloropt:# si on a l'option couleur
sys.stdout.write(color(term2find,tranche))
else:#si on a pas l'option couleur
# print tranche
sys.stdout.write(str(tranche))
logger.info("tranchefinal= <" + tranche + ">")
logger.info("tranchefinal= <" + color(term2find,tranche) + ">")
if nbrlinesopt:
tranche = str(str(nbrlines) + ":" + line)
else:
tranche = str(line)
#Sinon on ajoute la ligne à la tranche jusqu'à ce qu'on a isdate encore
else:
"""here tranche is equals to the date more the
others lines who not contain a date ^^"""
if nbrlinesopt:
tranche = tranche + str(str(nbrlines) + ":" + line)
else:
tranche = tranche + str(line)
logger.info("tranche = <" + tranche + ">")
if modesilencieux:
if countranche > 0 or nbrtanche > 0: #...si countranche ou nbrtanche...
#...le code retour sera 0
sortie_propre(0)
#...sinon...
else:
#...le code retour sera 1
sortie_propre(1)
else:# si on a pas le modesilencieux
if nbrtranche == 0:
logger.warning("Le terme " + term2find + " ne figure pas dans le fichier !")
if counttranches:
if countranche == 0:
logger.warning("Le terme " + term2find + " ne figure pas dans le fichier !")
else:#si countranche different de zero
print (str(countranche))
#close the file
file.close()
except IOError:
#affiche un message d'erreur lors de l'ouverture
logger.debug("Erreur le fichier " + str(file2lookinto) + " n'a pas pu être ouvert!")
sortie_propre(2)
except EOFError:#affiche un message d'erreur si on est en fin de fichier
logger.warning("Nous sommes a la fin du fichier")
sortie_propre(2)
if countranche or nbrtanche > 0: #...si countranche ou nbrtanche...
#...le code retour sera 0
sortie_propre(0)
#...sinon...
else:
#...le code retour sera 1
sortie_propre(1)
def sortie_propre(code_retour):
logger.debug("%%% FIN %%%")
sys.exit(code_retour)
#si le fichier est importer et ceci est considéré comme le main
if __name__ == '__main__':
#on assigne aux variables une valeur par default
regexopt=False
verbose = False
maxcountopt = False
helpcomplete = False
nbrtanche = 0
maxcount = 0
countranche = 0
counttranches = False
modesilencieux = False
ignorecase = False
term2find = None
file2lookinto= None
coloropt = False
nbrlinesopt = False
investigation = False
#lance la fonction analyse_commande
analyse_commande(sys.argv[1:])
# print logger.getEffectiveLevel();
# sortie_propre(0)
#lance la fonction searchinfile
searchinfile(term2find, file2lookinto)
sortie_propre(0)