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/

Répondre à