#!/usr/bin/python # -*- coding: utf-8 -*- # Logger Script # # Copyright (c) 2011 - Sebastian Silva # # This program 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 3 of the License, or # (at your option) any later version. # # This program 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, see . #from sugar.datastore import datastore #from sugar import profile import sys,csv,os,shutil from time import localtime, strftime, time, ctime, altzone, mktime, sleep from datetime import datetime from subprocess import Popen,PIPE,STDOUT try: from sqlite3 import dbapi2 as sqlite except: try: from pysqlite2 import dbapi2 as sqlite except: print "Advertencia: Imposible encontrar bilbiotecas pysqlite." ####################################################### def wait(time_lapse): sleep(time_lapse) #def wait(time_lapse): # """ Implementa un "sleep timer" compatible con GTK """ # time_start = time() # time_end = (time_start + time_lapse) # # while time_end > time(): # while gtk.events_pending(): # gtk.main_iteration() def execute_cmd(cmd): """ Ejecuta un comando de la terminal y retorna el output del comando. """ p = Popen(cmd, shell=True, bufsize=0, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) return child_stdout_and_stderr.read() def _read_file(path): """ Esta función lee y retorna el contenido de archivos de texto """ if os.access(path, os.R_OK) == 0: return "n/d" fd = open(path, 'r') value = fd.read() fd.close() if value: value = value.strip('\n') return value else: print "Error leyendo "+path return None class Data_general: """ Obtenemos y almacenamos datos para registrar """ def __init__(self): self.retrieved = False self.events = {} def event(self, hora, texto): try: if self.events[hora]: self.events[hora+1] = [ctime(hora), texto ] except KeyError: self.events[hora] = [ctime(hora), texto ] def collect_logs(self): """ recolecta la info de los logs de los historiales. """ log_dir = os.environ['HOME']+"/.sugar/default/logs" if not os.path.exists(log_dir): log_dir = "/home/olpc/.sugar/default/logs" if not os.path.exists(log_dir): return None # Navegar recursivamente los directorios de logs stack = [log_dir] mtime = 0 while stack: directory = stack.pop() for base in os.listdir(directory): name = os.path.join(directory, base) if os.path.isdir(name): if not os.path.islink(name): stack.append(name) else: mtime = os.path.getmtime(name) creation_time = os.path.getctime(name) # nota: creation time no es correcto pq los logs han sido movidos a subcarpetas this_dir = os.path.split(os.path.dirname(name))[1] if this_dir == "logs": #estamos mirando la sesión recien comenzada this_dir = "" if base == "shell.log": pass elif base == "datastore.log": pass elif base == "presenceservice.log": pass else: self.event(mtime, "LOG: Ultima actividad en " + name) else: #estamos mirando una sesión anterior if base == "datastore.log": pass elif base == "presenceservice.log": self.event(mtime, "LOG: *** %s - probable inicio de sesión" % name ) elif base == "shell.log": self.event(mtime, "LOG: Ultima actividad en log de shell, posible fin de sesión: " + name) else: self.event(mtime, "LOG: Ultima actividad en " + name) # Ahora vamos a iterar por todos los historiales de Navegador / Wikipedia isolation_dir = "/home/olpc/isolation/1/gid_to_data_dir" if not os.path.exists(isolation_dir): isolation_dir = "/home/olpc/.sugar/default" if not os.path.exists(isolation_dir): print "Imposible encontrar directorio de los registros del navegador." return None stack = [isolation_dir] while stack: directory = stack.pop() try: subdirs = os.listdir(directory) except: subdirs = [] for base in subdirs: name = os.path.join(directory, base) if os.path.isdir(name): if not os.path.islink(name): stack.append(name) else: if base == "places.db": shutil.copy (name, "/tmp") tmpname = os.path.join("/tmp", base) con = sqlite.connect(tmpname) cur = con.cursor() results = cur.execute ("select last_visit, uri, title, visits from places") for r in results: #item_timestamp = float(str(r[0])[:10]) item_timestamp = mktime( datetime.strptime(r[0], "%Y-%m-%d %H:%M:%S.%f").timetuple()) if r[1][:27] == 'http://localhost:8000/wiki/': self.event(item_timestamp, "WEB: (" + r[1] + ") - Articulo Wikipedia: " + r[1][27:] + " (vez %s)" % r[3]) elif r[1][:31] == 'http://localhost:8000/search?q=': self.event(item_timestamp, "WEB: (" + r[1] + ") - Se busca en Wikipedia: " + r[1][31:] + " (vez %s)" % r[3]) elif r[1][:29] == 'http://localhost:8000/static/': self.event(item_timestamp, "WEB: (" + r[1] + ") - Inicio de Wikipedia." + " (vez %s)" % r[3]) else: self.event(item_timestamp, "WEB: Navega a: (" + r[1] + ") (vez %s)" % r[3]) con.close() os.unlink(tmpname) return True def install_logger(self): #copiamos el ejecutable logdir = "/home/olpc/.logger" if not os.path.exists(logdir): execute_cmd("mkdir -p "+logdir) logprog = os.path.join(logdir, "logger.py") shutil.copy (sys.argv[0], logprog) #lo hacemos autoiniciar already_installed = False xsession = "/home/olpc/.xsession" if os.path.exists(xsession): contents = _read_file(xsession) for line in contents.splitlines(): if line == "python /home/olpc/.logger/logger.py &": already_installed = True if not already_installed: execute_cmd("echo 'python /home/olpc/.logger/logger.py &' >> " + xsession) def update_logger(self): if self.collect_logs(): logdir = "/home/olpc/.logger" logfile = "historial.csv" logpath = os.path.join(logdir, logfile) if not os.path.exists(logpath): execute_cmd("mkdir -p "+logdir) mtime = 0 else: #Obtenemos la fecha de la ultima entrada en el log lastlog = execute_cmd("tail -n1 "+logpath) lastlog = lastlog.strip('\n') try: mtime = float(lastlog[-11:-1]) except: mtime = 0 size = os.path.getsize(logpath) # poor mans logrotate if size>262144: #limit 256k if os.path.exists(logpath+"-3"): execute_cmd("mv "+logpath+"-3 "+logpath+"-4") if os.path.exists(logpath+"-2"): execute_cmd("mv "+logpath+"-2 "+logpath+"-3") if os.path.exists(logpath+"-1"): execute_cmd("mv "+logpath+"-1 "+logpath+"-2") execute_cmd("mv "+logpath+" "+logpath+"-1") s = os.statvfs(logdir) free_disk_in_mb = (s.f_bsize * s.f_bavail)/(1024*1024) if free_disk_in_mb > 30: fd = open(logpath,"a") writer = csv.writer(fd, dialect='excel') for ev in sorted(self.events): if ev > mtime: writer.writerow(self.events[ev]) #print self.events[ev] writer.writerow([ctime(time()), "LOGGER: Se actualizó registro de seguimiento *** " + str(int(time()))]) #print ctime() + " updated " + str(int(time())) #print ctime(mtime) + " :last log " + str(int(mtime)) fd.close() else: print "Imposible cargar logs." # Aquí comienza la ejecución if os.path.split(sys.argv[0])[-1:][0]=='logger.py': # Somos el sistema de seguimiento dg = Data_general() wait(30) dg.update_logger() elif os.path.split(sys.argv[0])[-1:][0]=='instalar.py': print "Instalador." dg = Data_general() dg.install_logger() dg.update_logger() print "Se ha instalado el programa de seguimiento."