def delete_date(date): """ Mira en la lista de días procesados. Si existe el día elimina los registros y borra el día en dicha lista de procesados. """ year = date.strftime('%Y') if db_name == 'analysis' or db_name == 'test_analysis': if getConfig().is_processed_for(date, 'analysis'): del_row_query_for_analysis("actions", date) del_row_query_for_analysis("saved", date) del_row_query_for_analysis("visited", date) getConfig().remove_from_processed_list(date, 'analysis') print "\tDeleted rows for " + str(date) # elimina las tablas si no existe ningún registro para el año if getConfig().year_not_exists_in_list(year, 'analysis'): del_table_query_for_analysis("actions", year) del_table_query_for_analysis("saved", year) del_table_query_for_analysis("visited", year) print "Deleted tables for " + year # si la fecha dada no está procesada pero su año aparece en la lista # de fechas procesadas (log.analysis.processed).. elif not getConfig().year_not_exists_in_list(year, 'analysis'): print "\t\t" + str(date) + " not in processed list for " + db_name else: if getConfig().is_processed_for(date, 'squidlogs'): del_row_query_for_squidlogs(date) getConfig().remove_from_processed_list(date, 'squidlogs') print "Deleted rows for " + str(date) elif not getConfig().year_not_exists_in_list(year, 'squidlogs'): print "\t" + str(date) + " not in processed list for " + db_name
def run(date): global log_filename log_filename = getConfig().get_log_filename(date) squidlogs_processed = getConfig().is_processed_for(date, 'squidlogs') if not squidlogs_processed: log_msg2("Ejecutando wikisquilter sobre " + log_filename) run_wsq(date) log_msg_ok2() else: log_msg2(log_filename + " ya fue anteriormente procesado por WikiSquilter.", state='processed')
def run(date): """ Transfiere de remoto a local un log para una fecha dada. """ log_name = getConfig().get_log_filename(date) dir_local = getConfig().get_dir_local_logs() dir_remote = getConfig().get_dir_remote_logs() # # Si no aparece como descargado o aparece como descargado pero no existe.. downloaded = getConfig().is_processed_for(date, 'transfer') if not downloaded or (downloaded and not file_exists(dir_local + log_name)): log_msg2("Descargando " + log_name + " desde equipo remoto..") # si aparece como descargado lo quitamos primero de la lista.. if downloaded: getConfig().remove_from_processed_list(date, 'transfer') # # Transferimos.. cmd = "scp " + dir_remote + log_name + " " + dir_local exec_proc(cmd) # De esta forma nos aseguramos que el log fue descargado por completo: getConfig().add_to_processed_list(date, 'transfer') log_msg_ok2() else: log_msg2(log_name + " no es necesario descargar de nuevo.", state='processed')
def is_new_year(table_name): """ Mira en el txt el año y si no hay fecha alguna procesada para ese año entonces devolverá True """ # si el fichero no tiene nada devolvemos False para no crear luego una tabla vacia if is_empty(TXT_FILE): log_msg4("WARNING: No se puede obtener el año del dump.txt vacío!!") return False else: # si el fichero no está vacío lo leemos para comprobar el año f = open(TXT_FILE) f.readline() # la primera linea no interesa. Leemos la segunda y sacamos el # año eligiendo el primer grupo (\d{4}) de la expresión regular # que coincide con dicha línea l = f.readline() m = re.match(".*(\d{4})\-\d{2}.*", l) # seteamos txt_year con el año del dumped.txt global txt_year txt_year = m.group(1) # miramos si en la lista de procesados (logs.processed) # aparece alguno ya procesado para el año del txt, # lo cual quiere decir que ya existe la tabla return getConfig().year_not_exists_in_list(txt_year, 'analysis')
def wsq_to_txt(table_name, date): """ Vuelca en tmp/dumped.txt el resultado de la query a la BD squidlogs """ if(table_name == 'visited'): query = "select date(f_date_time), substr(dayname(f_date_time),1,2), " + \ "f_lang_id, f_ns_id, count(*) " + \ "from Filtered where f_action_id is null " + \ "and date(f_date_time) = '" + date.strftime('%Y-%m-%d') + "' " + \ "group by date(f_date_time), f_lang_id, f_ns_id;" elif(table_name == 'saved'): query = "select date(f_date_time), substr(dayname(f_date_time),1,2), " + \ "f_lang_id, f_ns_id, count(*) " + \ "from Filtered where f_action_id = 2 " + \ "and date(f_date_time) = '" + date.strftime('%Y-%m-%d') + "' " + \ "group by date(f_date_time), f_lang_id, f_ns_id;" elif(table_name == 'actions'): query = "select date(f_date_time), substr(dayname(f_date_time),1,2), " + \ "f_action_id, f_lang_id, f_ns_id, count(*) " + \ "from Filtered where f_action_id in (0, 1, 3, 4) " + \ "and date(f_date_time) = '" + date.strftime('%Y-%m-%d') + "' " + \ "group by date(f_date_time), f_action_id, f_lang_id, f_ns_id;" log_msg4("Creando dump para " + table_name) exec_mysql(getConfig().db_name_squidlogs, query=query, dumped=True) log_msg_ok4()
def del_row_query_for_squidlogs(date): """ Ejecuta la query sobre squidlogs para eliminar los registros para la fecha dada """ query = "DELETE FROM Filtered " + \ "WHERE date(f_date_time) = '" + date.strftime('%Y-%m-%d') + "'" exec_mysql(getConfig().db_name_squidlogs, query=query)
def exec_mysql(database, **kwargs): """ Ejecuta la query, ya sea especificada en un String o se cargue desde un archivo .sql http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/ **kwargs puede estar vacío o contener un hash con las siguientes claves: * query: indica la query a ejecutar * dumped: si tiene valor 'True' volcará el resultado de la query sobre un fichero dumped.txt * options: esta clave tiene como valor un array de Strings, de modo que en el comando mysql 'cmd' se inyectarán tantas opciones de ejecución como elementos posea dicho array * sql_file: indica el archivo .sql a ejecutar (en lugar de una query) Por ejemplo si kwargs['options'] = ['local-infile'], entonces se ejecutaría así: mysql --local-infile -D..[resto de argumentos] Si hay error de 'acceso denegado' hay que dar este permiso: http://dev.mysql.com/doc/refman/5.0/es/access-denied.html GRANT FILE ON *.* TO 'ajreinoso'@'localhost'; """ # Dejamos estos 2 valores por defecto options = [] dumped = False query = None sql_file = None # seteamos cada variable según el contenido de kwargs for key in kwargs: if key == 'dumped': dumped = kwargs[key] elif key == 'options': options = kwargs[key] elif key == 'query': query = kwargs[key] elif key == 'sql_file': sql_file = kwargs[key] # creamos el archivo query.sql si no recibimos la opción sql_file='archivo.sql' sql_file = create_sql_file(query) if not sql_file else sql_file # construimos el comando 'cmd' cmd = "mysql " for option in options: cmd += "--" + option + " " cmd += "-D " + database + " -u " + DB_USER + " -p" + DB_PASS + \ " < " + sql_file if dumped: cmd += " > " + getConfig().get_dumped_txt_filename() # ejecutamos el comando exec_proc(cmd)
def del_table_query_for_analysis(table_name, year): """ Ejecuta la query sobre analysis para eliminar las tablas para el año dado """ # http://dev.mysql.com/doc/refman/5.0/en/delete.html query = "DROP TABLE IF EXISTS " + table_name + year exec_mysql(getConfig().db_name_analysis, query=query)
def run_for_day(date): """ Ejecuta todas la tareas para procesar el día dado """ day = getConfig().get_log_date(date) # Si la fecha dada no está procesada por completo (para squidlogs y analysis).. if not getConfig().is_full_processed(date): log_msg("---- Procesando día " + day + " ----") # transferimos de remoto a local transfer_log.run(date) # ejecutamos wsq run_wikisquilter.run(date) # populamos analysis desde squidlogs populate_analysis.run(date) else: log_msg("#### No es necesario procesar el día " + day + " ####")
def del_row_query_for_analysis(table_name, date): """ Ejecuta la query sobre analysis para eliminar los registros de una tabla y fecha dada """ # http://dev.mysql.com/doc/refman/5.0/en/delete.html query = "DELETE FROM " + table_name + date.strftime('%Y') + \ " WHERE day = '" + str(date) + "'" exec_mysql(getConfig().db_name_analysis, query=query)
def run(date): """ POPULA VISITEDYYYY, SAVEDYYYY y ACTIONSYYYY (YYYY corresponde al año, por ejemplo 'SAVED2013') """ global new_tables_created new_tables_created = False analysis_processed = getConfig().is_processed_for(date, 'analysis') if not analysis_processed: log_msg2('Populando analysis') populate('visited', date) populate('saved', date) populate('actions', date) getConfig().add_to_processed_list(date, 'analysis') log_msg_ok2() else: log_msg2( 'La fecha ' + date.strftime('%Y-%m-%d') + ' ya fue anteriormente ' 'procesada para analysis.', state='processed')
def create_sql_file(query): """ Crea un archivo [carpeta_archivos_temporales]/query.sql con una query dada. Finalmente se devuelve nombre del archivo .sql junto a su ruta absoluta """ sql_file = getConfig().get_dir_tmp() + "query.sql" # escribimos la query en un .sql temporal f = open(sql_file, "w") f.write(query) f.close() return sql_file
def run(): DB_USER = getConfig().get_db_user() DB_NAME = getConfig().get_db_name('squidlogs') DB_HOST = getConfig().get_db_host() query = "DROP DATABASE IF EXISTS " + DB_NAME + ";" + \ "CREATE DATABASE " + DB_NAME + " DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;" + \ "GRANT ALL PRIVILEGES ON `" + DB_NAME + "` . * " + \ "TO '" + DB_USER + "'@'" + DB_HOST + "' WITH GRANT OPTION ;" + \ "GRANT ALL PRIVILEGES ON `" + DB_NAME + "` . * " + \ "TO '" + DB_USER + "'@'%' WITH GRANT OPTION ;" log_msg2("Limpiando B.D. squidlogs") log_msg3("Creando BD..") exec_mysql_query(DB_NAME, query=query) log_msg_ok3() log_msg3("Creando tablas..") exec_mysql_query(DB_NAME, sql_file='squidlogs_tables.sql') log_msg_ok3() log_msg_ok2()
def init_logger(module): """ Inicializa el logger para escribir en un archivo el historial completo de ejecución del script """ d = datetime.now() filename = getConfig().get_dir_run_history() if getConfig().test_mode: filename += "test." filename += module + "-" + d.strftime('%Y%m%d_%H%M') + ".log" logging.basicConfig( filename=filename, format='%(asctime)s - %(message)s', # http://docs.python.org/2/howto/logging.html#displaying-the-date-time-in-messages # http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior datefmt='%b,%d %H:%M', level=logging.INFO, filemode='w' ) print "Creado historial de ejecución en " + filename
############### # # MAIN # ############### args = init_argparser( test='Removes only test regs in chosen database', database='Especify database name', date='Delete regs from database between 2 dates or just one') test_mode = True if args.test else False setConfig(test_mode=test_mode) # nombre de la base de datos en la cual eliminar los registros db_name = getConfig().db_name_squidlogs if args.database[0] == 'squidlogs' \ else getConfig().db_name_analysis from helpers.mysql_helper import exec_mysql # crea diálogo de confirmación en caso de no ejecutar en modo test if not test_mode: ans = raw_input("WARNING: Not in test mode. Type " + db_name + " to continue..\n") if ans != db_name: print "Exiting without changes.." sys.exit(0) print "Deleting data in " + db_name + ".." if len(args.date) == 1:
def run_wsq(date): """ Ejecutamos wikisquilter sobre el log de la fecha dada """ DB_USER = getConfig().get_db_user() DB_PASS = getConfig().get_db_password() DB_NAME = getConfig().db_name_squidlogs DB_HOST = getConfig().get_db_host() DB_PORT = getConfig().get_db_port() LOGS_DIR = getConfig().get_dir_local_logs() LOG_MONTH = getConfig().get_log_month(log_filename) SQUIDLOGFILES_DIR = getConfig().get_dir_squidlogfiles() # copiamos el log a procesar a la carpeta wikisquilter/squidlogfiles log_msg3("Copiando " + log_filename + " a la carpeta 'squidlogfiles'") # cambiamos al directorio /wikisquilter desde donde ejecutamos este script os.chdir(getConfig().get_dir_wikisquilter()) try: copy(LOGS_DIR + log_filename, SQUIDLOGFILES_DIR) except IOError as err: halt(err) log_msg_ok3() # # Según la lista de logs procesados 'logs.processed' esté vacía o no # se escogerá una opción u otra. # # -d Elimina todas las tablas existentes en squidlogs y crea nuevas vacías # para insertar en ellas únicamente los datos de la fecha a procesar. # -a Añade a las tablas existentes los datos procesados, sin eliminar # por tanto las anteriores fechas procesadas de squidlogs # (las tablas deben existir). # # Si se escoge -a entonces # OPTION = '-d' if getConfig().is_processed_list_empty('squidlogs') else '-a' # ejecutamos wikisquilter cmd = "java -cp " + \ "./build/classes:./dist/lib/mysql-connector-java-5.1.5-bin.jar " + \ "wikisquilter.Main " + \ "'jdbc:mysql://" + DB_HOST + ":" + DB_PORT + "/" + \ DB_NAME + "' " + DB_USER + " " + DB_PASS + \ " AllRequests Filtered Searches " + \ "cfgWPFilter.xml " + \ "./squidlogfiles -f " + log_filename + " " + LOG_MONTH + " " + \ "sal33.txt err33.txt " + OPTION + " -f -i -r &" log_msg3("Ejecutando") exec_proc(cmd) log_msg_ok3() # eliminamos el log procesado de la carpeta wikisquilter/squidlogfiles log_msg3("Eliminando " + log_filename + " de la carpeta 'squidlogfiles'") try: os.remove(SQUIDLOGFILES_DIR + log_filename) except OSError as err: halt(err) log_msg_ok3() # vuelvo al directorio padre para que no haya problema a la hora de # ejecutar el siguiente módulo, ya que para ejecutar wikisquilter estábamos en /wikisquilter # os.chdir("..") getConfig().add_to_processed_list(date, 'squidlogs')
#!/usr/bin/python # -*- coding: utf8 -*- # Nos ayudará para interactuar con la BD from exec_helper import exec_proc from helpers.config_helper import getConfig DB_USER = getConfig().get_db_user() DB_PASS = getConfig().get_db_password() def create_sql_file(query): """ Crea un archivo [carpeta_archivos_temporales]/query.sql con una query dada. Finalmente se devuelve nombre del archivo .sql junto a su ruta absoluta """ sql_file = getConfig().get_dir_tmp() + "query.sql" # escribimos la query en un .sql temporal f = open(sql_file, "w") f.write(query) f.close() return sql_file def exec_mysql(database, **kwargs): """ Ejecuta la query, ya sea especificada en un String o se cargue desde un archivo .sql
#!/usr/bin/python # -*- coding: utf8 -*- import re from helpers.utils import is_empty from helpers.config_helper import getConfig from helpers.logging_helper import log_msg2, log_msg3, log_msg4, log_msg_ok2, log_msg_ok3, log_msg_ok4 from helpers.mysql_helper import exec_mysql DB_NAME = getConfig().db_name_analysis TEST_MODE = getConfig().test_mode TXT_FILE = getConfig().get_dumped_txt_filename() # indica el año del txt donde se vuelca el resultado de la query a squidlogs txt_year = "" # indica si se crearon ya las tablas nuevas new_tables_created = False def get_table_name_year(table_name): """ Devuelve el nombre de la tabla junto con el año obtenido del .txt generado por la query a squidlogs """ return table_name + txt_year def wsq_to_txt(table_name, date): """ Vuelca en tmp/dumped.txt el resultado de la query a la BD squidlogs