#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 Michel Blockelet # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This file is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. """Plugin munin pour innd :: donne le nombre total de posts par newsgroup.""" ## Importations import socket, sys, threading, time ## Configuration # Fichier de cache pour stocker les données entre deux lancements cache_file = "/tmp/munin_innd_total_cache" # Effectuer le compte exact du nombre de messages (beaucoup plus lent) # sinon, utilise le compte approximatif envoyé par le serveur exact_count = False # Nombre de messages minimal pour être affiché min_messages = 100 def recvlines(sock): buff = sock.recv(4096) while buff[-3] != '.': buff += sock.recv(4096) return buff.split('\r')[:-2] def get_newsgroups_data(): ## Connexion s = socket.socket() s.connect(('localhost', 119)) ## Mise en mode reader (pour utiliser 'listgroup') s.send("mode reader\r\n") # Petit "hack" en attendant d'utiliser la nntplib time.sleep(0.5) s.recv(4096) ## Récupération des newsgroups et du nombre de posts s.send("list\r\n") newsgroups = [] for l in recvlines(s)[1:]: name = l.split()[0] # Conversion du nom vers un format accepté par munin cname = name while '.' in cname: (parent, sep, sub) = cname.partition('.') cname = '%s_%s' % (parent[0], sub) cname = cname.replace('-', '_') # Récupération du nombre de posts if exact_count: s.send('listgroup %s\r\n' % name) val = len(recvlines(s)) else: s.send('group %s\r\n' % name) val = int(s.recv(4096).split()[1]) # On ne garde pas les newsgroups presque vides if val > min_messages: newsgroups.append((name, cname, val)) ## On garde un cache si jamais le serveur nous bounce if len(newsgroups) > 0: try: f = open(cache_file, 'w') for ngdata in newsgroups: f.write('%s,%s,%d\n' % ngdata) f.close() except: pass else: try: for line in open(cache_file, 'r'): newsgroups.append(line.strip().split(',')) except: pass return newsgroups ## Sortie if len(sys.argv) > 1 and sys.argv[1] == 'config': # Configuration du graphe print 'host_name news.crans.org' print 'graph_title Nombre total de posts' print 'graph_args --base 1000 --lower-limit 0' print 'graph_vlabel posts' print 'graph_category News' print 'graph_info Nombre de posts pour chaque newsgroup' rnewsgroups = get_newsgroups_data() (ng0, cng0, val0) = rnewsgroups[0] print '%s.label %s' % (cng0, ng0) print '%s.draw AREA' % cng0 for (ng, cng, val) in rnewsgroups[1:]: print '%s.label %s' % (cng, ng) print '%s.draw STACK' % cng print 'total.label Total' else: # On lance un thread pour éviter les timeouts finished = threading.Event() def thread_gnd(return_newsgroups, finished): return_newsgroups.extend(get_newsgroups_data()) finished.set() rnewsgroups = [] t = threading.Thread(target=thread_gnd, args=(rnewsgroups, finished)) t.daemon = True t.start() # On laisse 30 secondes pour que le thread finisse finished.wait(30) if finished.isSet(): fnewsgroups = rnewsgroups else: try: for line in open(cache_file, 'r'): fnewsgroups.append(line.strip().split(',')) except: fnewsgroups = [] # Envoi des valeurs lines = [] total = 0 for (ng, cng, val) in fnewsgroups: total += val print '%s.value %d' % (cng, val) print 'total.value %d' % total