def showMergedRRDs(server, template_name, outfile='-', start=0, duration=0, details=1, timezone=0): """showMergedRRDs""" host = Host.by_name(server) if host is None: raise RRDNotFoundError, server graph = Graph.by_host_and_name(host, template_name) if graph is None: LOGGER.error("ERROR: The template '%(template)s' does not exist. " "Available templates: %(available)s", { 'template': template_name, 'available': ", ".join([g.name for g in host.graphs]), }) # Copie en profondeur pour éviter des écrasements # de valeurs entre threads (ticket #549). template = copy.deepcopy(conffile.templates[graph.template]) template["name"] = template_name template["vlabel"] = graph.vlabel template["last_is_max"] = graph.lastismax template["cdefs"] = graph.cdefs if graph.min is not None: template["min"] = graph.min if graph.max is not None: template["max"] = graph.max ds_map = {} ds_list = graph.perfdatasources for ds in ds_list: ds_map[ds.name] = getEncodedFileName(server, ds.name) tmp_rrd = RRD(filename=ds_map, server=server) tmp_rrd.graph(template, ds_list, outfile, start=start, duration=duration, details=(int(details)==1), timezone=timezone)
def exportCSV(server, graphtemplate, ds, start, end, timezone): """ export CSV # valeurs finales -> dictionnaire # - renseigné a partir dictionnaires obtenus pour chaque indicateur # - sous la forme : # * cle = indice # * valeur = [TimeStamp, donnee dictionnaire1 pour TimeStamp, ..., # donnee dictionnaireN pour TimeStamp @param server : serveur @type server : C{str} @param graphtemplate : graphe @type graphtemplate : C{str} @param ds : indicateur graphe @type ds : C{str} @param start : debut plage export @type start : C{str} @param end : fin plage export @type end : C{str} @param timezone : Décalage en minutes du fuseau horaire de l'utilisateur (utilisé pour obtenir une représentation textuelle des dates). @type timezone : C{int} @return : donnees RRD d apres server, indicateur et plage @rtype: dictionnaire """ # initialisation host = Host.by_name(server) graph = Graph.by_host_and_name(host, graphtemplate) delta = pytz.FixedOffset(-timezone) # Si l'indicateur est All ou n'existe pas pour cet hôte, # tous les indicateurs sont pris en compte. if not ds or ds.lower() == "all": ds_list = [pds.name.encode('utf-8') for pds in graph.perfdatasources] elif isinstance(ds, unicode): ds_list = [ds.encode('utf-8')] else: ds_list = [str(ds)] ds_map = {} for ds in ds_list: ds_map[ds] = getEncodedFileName(server, ds) headers = ['Timestamp', 'Date'] headers.extend(ds_list) # Construction d'une liste de listes contenant un horodatage # et les valeurs des différents indicateurs sélectionnés. # L'horodatage arrive toujours en premier. Ensuite, les valeurs # arrivent dans l'ordre des indicateurs donnés dans ds_list. result = [] format_date = config.get('csv_date_format', "long") format_value = asbool(config.get('csv_respect_locale', False)) date_locale = 'en_US' # Au cas où la configuration serait changée dynamiquement. if not format_value: locale.setlocale(locale.LC_NUMERIC, 'C') locale.setlocale(locale.LC_TIME, 'C') else: try: lang = request.accept_language.best_matches() except TypeError: # Lorsque le thread n'a pas de "request" associée # (ex: dans les tests unitaires), TypeError est levée. lang = [] for tentative_lang in lang: try: tentative_lang = tentative_lang.replace('-', '_') # Pour le formattage des nombres. locale.setlocale(locale.LC_NUMERIC, tentative_lang) # Pour le formattage des dates/heures. locale.setlocale(locale.LC_TIME, tentative_lang) except locale.Error: pass else: LOGGER.debug(u"Preparing to format CSV values, " "using locale %r" % tentative_lang) date_locale = tentative_lang break for ds in ds_list: tmp_rrd = RRD(filename=ds_map[ds], server=server) # Récupère les données de l'indicateur sous la forme suivante : # dict(timestamp1=[valeur1], timestamp2=[valeur2], ...) # Les valeurs sont des listes car un fichier peut potentiellement # contenir plusieurs indicateurs. Ce n'est pas le cas sur Vigilo # où la liste de valeurs contiendra TOUJOURS une seule valeur. values_ind = tmp_rrd.fetchData( ds_names=['DS'], start_a=start, end_a=end) for index, timestamp in enumerate(values_ind): # Si l'index n'existe pas encore dans le résultat, # c'est qu'il s'agit du premier indicateur que l'on traite. # On ajoute donc le timestamp à la liste avant tout. if len(result) <= index: # Le timestamp est ajouté, une première fois sous forme # d'horodatage UNIX à destination de scripts et une seconde # fois sous forme textuelle à destination des exploitants. # 1. On convertit le timestamp depuis UTC vers le fuseau # horaire donné par le navigateur de l'utilisateur. date = pytz.utc.localize(datetime.datetime.utcfromtimestamp( timestamp)).astimezone(delta) # 2. On utilise la représentation des dates/heures issue # de la locale de l'utilisateur (ou "en_US" par défaut). date = babel.dates.format_datetime(date, format_date, locale=date_locale) result.append([timestamp, date]) # On prépare le format adéquat en fonction du type de la valeur. # Le formattage tiendra compte de la locale. # Exemples pour le français : # int(1234) -> "1 234" # float(1234.56) -> "1234,56" format_for_value = isinstance(values_ind[timestamp][0], int) and \ '%d' or '%f' value = (values_ind[timestamp][0] is not None) and \ locale.format(format_for_value, values_ind[timestamp][0]) or \ None result[index].append(value) # On trie les valeurs par horodatage ascendant. result = sorted(result, key=lambda r: int(r[0])) # Écriture de l'en-tête, puis des données dans un buffer. # Le contenu final du buffer correspond au fichier CSV exporté. buf = StringIO() quoting = config.get('csv_quoting', 'ALL').upper() if quoting not in ('ALL', 'MINIMAL', 'NONNUMERIC', 'NONE'): quoting = 'ALL' csv_writer = csv.writer(buf, delimiter=config.get("csv_delimiter_char", ';'), escapechar=config.get("csv_escape_char", '\\'), quotechar=config.get("csv_quote_char", '"'), quoting=getattr(csv, 'QUOTE_%s' % quoting)) csv_writer.writerow(headers) csv_writer.writerows(result) return buf.getvalue()