Le 01/12/2010 15:09, Greg a écrit :
Bonjour,
j'ai des centaines de crons, définie dans une 10ène de crontabs. Le
tout géré par des développeurs... (c'est un autre débat).
Je voudrais optimiser leur répartition dans le temps.
Il y a des crons qui tournent toutes les minutes, les 3 minutes, à
certaines heures, bref de tout.
On se rend compte facilement qu'à chaque heure à la minute 0, on a
plein de crons qui se lancent... et c'est aussi le cas à d'autres
minutes.
Est-ce que vous connaisseriez, ou auriez fait un outils qui permet
d'avoir un affichage graphique du nombre de crons lancés par minutes,
sur une journée ? Avec par exemple des couleurs qui tendent vers le
foncé quand il y a beaucoup de crons qui se lancent dans la même
minute... Un peu comme dans la "combined map" de visitors :
http://www.hping.org/visitors/report.html
Ainsi, je pourrais me rencontre facilement des minutes saturées, et
déplacer ces crons à m+1 ou m+n...
J'ai finalement fais un script très rapide en Python, attaché à ce mail.
Il prends des crontabs en entrée (stdin), donc vous pouvez utiliser vos
outils préférés (ssh, find, xargs, cat, ...) pour les piper dedans, puis
il affiche un tableau avec les heures d'une journée en axe X et les
minutes en axe Y, avec des couleurs (rouge = pas bien, vert = dispo).
Il ne gère pas les lignes de crontabs spéciales (@reboot par exemple),
mais de toute façon on s'en fiche le but étant de voir les minutes saturées.
Pardonnez le manque de commentaires et de debug, j'ai fais ça à
l'arrache, ça fonctionne avec mes crontabs, je vais pas plus loin ;)
Bon week-end.
--
Greg
#!/usr/bin/python -O
# -*- coding: iso-8859-1 -*-
#
#######################################################################
#
# Copyright (c) 2010 Grégory Duchatelet <[email protected]>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
#######################################################################
"""
Display a daily colored map of runned crons
"""
__revision__ = "$Rev: 5198 $"
import sys
import re
import types
class CronParser:
weekdays = {0:'SUN',
1:'MON',
2:'TUE',
3:'WED',
4:'THU',
5:'FRI',
6:'SAT',
7:'SUN'}
months = {1:'JAN',
2:'FEB',
3:'MAR',
4:'APR',
5:'MAY',
6:'JUN',
7:'JUL',
8:'AUG',
9:'SEP',
10:'OCT',
11:'NOV',
12:'DEC'}
re_number = '\d{1,2}'
re_interval = re.compile('^(%s-%s)$' % (re_number, re_number))
re_separated = re.compile('^(%s;%s)$' % (re_number, re_number))
re_full = re.compile('^(\*)$')
re_alone = re.compile('^(\d+)$')
re_intercalated = re.compile('^(\d+)-(\d+)\b?/(\d+)$')
re_full_intercalated = re.compile('^[\*]\b?/(\d+)$')
re_zero_full_intercalated = re.compile('^0\b?/(\d+)$')
def parse(self, expression, start=1, end=31, zero_full=False):
result = []
expression_parts = expression.split(';')
for exp in expression_parts:
# If it's full, don't verify the rest
if self.re_full.match(exp):
return range(start, end + 1)
elif exp == '0' and zero_full:
return range(start, end + 1)
elif exp == '0' and not zero_full:
return [start]
elif exp.find(',') > 0:
for v in exp.split(","):
result.extend(self.parse(v, start, end,
zero_full))
return result
elif self.re_full_intercalated.match(exp) or\
(self.re_zero_full_intercalated.match(exp) and zero_full):
try:
step =
int(self.re_full_intercalated.match(exp).groups()[0])
except:
raise Exception("Wrong step!")
return range(start, end + 1, step)
elif self.re_interval.match(exp):
intervals = self.re_interval.match(exp).groups()
for inter in intervals:
numbers = re.findall("(%s)" %
self.re_number, inter)
if len(numbers) != 2:
raise Exception("")
numbers_range = range(int(numbers[0]),
int(numbers[1])+1)
result += numbers_range
elif self.re_intercalated.match(exp):
i = self.re_intercalated.match(exp).groups()
result += range(int(i[0]),int(i[1]),int(i[2]))
elif self.re_alone.match(exp):
result.append(int(exp))
else:
raise Exception("Wrong parameter: '%s'" % exp)
res = []
for i in result:
if i < start or i > end:
raise Exception("Expression '%s' out of
boundaries. Start at %s until %s"\
% (i, start, end))
if i not in res:
res.append(i)
del(result)
res.sort()
return res
def parse_day(self, expression):
return self.parse(expression, 1, 31)
def parse_month(self, expression):
return self.parse(self.__convert_expression(expression,
self.months), 1, 12)
def parse_hour(self, expression):
return self.parse(expression, 0, 23)
def parse_minute(self, expression):
return self.parse(expression, 0, 59)
def parse_weekday(self, expression):
return self.parse(self.__convert_expression(expression,
self.weekdays), 0, 7)
def __convert_expression(self, expression, conv_dic):
expression = expression.upper()
for i in conv_dic:
expression = str(i).join(expression.split(conv_dic[i]))
return expression
if __name__ == '__main__':
re_split = re.compile("\s+")
re_start_dec = re.compile("^[\d\*]")
minutes = [0 for i in range(60*24)]
# parse crontabs from stdin
while True:
line = sys.stdin.readline()
if not line:
break
if not re_start_dec.match(line):
continue
parts = re_split.split(line)
for minute in CronParser().parse_minute(parts[0]):
for hour in CronParser().parse_hour(parts[1]):
if type(hour) == types.ListType:
for h in hour:
m = h*60 + minute
minutes[m] += 1
else:
m = hour*60 + minute
minutes[m] += 1
# header
header = "M/H| "
for th in range(24):
header += "%02d "%th
print '\x1b[48;5;4m%s\x1b[0m'%header
# find the maxcrons value
maxcrons = 0
for value in minutes:
if value > maxcrons:
maxcrons = value
# tab
for tm in range(60):
hline = "\x1b[48;5;4m[%02d]\x1b[0m "%tm
for th in range(24):
# minute index
m = th*60 + tm
# find a cool color
color = ""
if minutes[m] > int(maxcrons-(maxcrons*20/100)):
color = 1
elif minutes[m] > int(maxcrons-(maxcrons*30/100)):
color = 9
elif minutes[m] > int(maxcrons-(maxcrons*40/100)):
color = 3
elif minutes[m] > int(maxcrons-(maxcrons*50/100)):
color = 8
elif minutes[m] > int(maxcrons-(maxcrons*60/100)):
color = 7
elif minutes[m] > int(maxcrons-(maxcrons*70/100)):
color = 6
elif minutes[m] > int(maxcrons-(maxcrons*80/100)):
color = 2
else:
color = 0
hline += "\x1b[48;5;%sm%02d\x1b[0m|"%(color, minutes[m])
# finally, print the colored line
print hline
_______________________________________________
Liste de diffusion du FRsAG
http://www.frsag.org/