2012-10-05 23:28:47 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
"""
|
|
|
|
***************************************************************************
|
2013-08-12 20:44:27 +02:00
|
|
|
ProcessingLog.py
|
2012-10-05 23:28:47 +02:00
|
|
|
---------------------
|
|
|
|
Date : August 2012
|
|
|
|
Copyright : (C) 2012 by Victor Olaya
|
|
|
|
Email : volayaf at gmail dot com
|
|
|
|
***************************************************************************
|
|
|
|
* *
|
|
|
|
* 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 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************
|
|
|
|
"""
|
|
|
|
|
|
|
|
__author__ = 'Victor Olaya'
|
|
|
|
__date__ = 'August 2012'
|
|
|
|
__copyright__ = '(C) 2012, Victor Olaya'
|
2013-10-01 20:52:22 +03:00
|
|
|
|
2012-10-05 23:28:47 +02:00
|
|
|
# This will get replaced with a git SHA1 when you do a git archive
|
2013-10-01 20:52:22 +03:00
|
|
|
|
2012-10-05 23:28:47 +02:00
|
|
|
__revision__ = '$Format:%H$'
|
|
|
|
|
2013-10-01 20:52:22 +03:00
|
|
|
import re
|
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
|
|
|
import os
|
2012-09-15 18:25:25 +03:00
|
|
|
import codecs
|
2013-04-16 15:41:04 +04:00
|
|
|
import datetime
|
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
|
|
|
from processing.tools.system import userFolder
|
2013-08-12 20:44:27 +02:00
|
|
|
from processing.core.ProcessingConfig import ProcessingConfig
|
2015-05-20 19:33:47 +02:00
|
|
|
from qgis.core import *
|
2013-04-16 15:41:04 +04:00
|
|
|
|
2015-08-22 14:29:41 +02:00
|
|
|
|
2013-10-01 20:52:22 +03:00
|
|
|
class ProcessingLog:
|
|
|
|
|
|
|
|
LOG_ERROR = 'ERROR'
|
|
|
|
LOG_INFO = 'INFO'
|
|
|
|
LOG_WARNING = 'WARNING'
|
|
|
|
LOG_ALGORITHM = 'ALGORITHM'
|
2015-10-01 09:06:33 +02:00
|
|
|
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
2012-09-15 18:25:25 +03:00
|
|
|
recentAlgs = []
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def startLogging():
|
2013-08-12 20:44:27 +02:00
|
|
|
if os.path.isfile(ProcessingLog.logFilename()):
|
2013-10-01 20:52:22 +03:00
|
|
|
logfile = codecs.open(ProcessingLog.logFilename(), 'a',
|
|
|
|
encoding='utf-8')
|
2012-09-15 18:25:25 +03:00
|
|
|
else:
|
2013-10-01 20:52:22 +03:00
|
|
|
logfile = codecs.open(ProcessingLog.logFilename(), 'w',
|
|
|
|
encoding='utf-8')
|
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
|
|
|
logfile.write('Started logging at ' +
|
|
|
|
datetime.datetime.now().strftime(
|
2015-10-01 09:06:33 +02:00
|
|
|
ProcessingLog.DATE_FORMAT) + '\n')
|
2012-09-15 18:25:25 +03:00
|
|
|
logfile.close()
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def logFilename():
|
2013-10-01 20:52:22 +03:00
|
|
|
batchfile = userFolder() + os.sep + 'processing.log'
|
2012-09-15 18:25:25 +03:00
|
|
|
return batchfile
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def addToLog(msgtype, msg):
|
2013-10-01 20:52:22 +03:00
|
|
|
try:
|
|
|
|
# It seems that this fails sometimes depending on the msg
|
|
|
|
# added. To avoid it stopping the normal functioning of the
|
|
|
|
# algorithm, we catch all errors, assuming that is better
|
|
|
|
# to miss some log info that breaking the algorithm.
|
|
|
|
if msgtype == ProcessingLog.LOG_ALGORITHM:
|
2015-05-20 19:33:47 +02:00
|
|
|
line = msgtype + '|' + datetime.datetime.now().strftime(
|
2015-10-02 21:06:19 +02:00
|
|
|
ProcessingLog.DATE_FORMAT) + '|' \
|
2015-08-22 14:29:41 +02:00
|
|
|
+ msg + '\n'
|
2015-05-20 19:33:47 +02:00
|
|
|
logfile = codecs.open(ProcessingLog.logFilename(), 'a',
|
|
|
|
encoding='utf-8')
|
|
|
|
logfile.write(line)
|
|
|
|
logfile.close()
|
|
|
|
algname = msg[len('Processing.runalg("'):]
|
2013-10-01 20:52:22 +03:00
|
|
|
algname = algname[:algname.index('"')]
|
|
|
|
if algname not in ProcessingLog.recentAlgs:
|
|
|
|
ProcessingLog.recentAlgs.append(algname)
|
|
|
|
recentAlgsString = ';'.join(ProcessingLog.recentAlgs[-6:])
|
|
|
|
ProcessingConfig.setSettingValue(
|
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
|
|
|
ProcessingConfig.RECENT_ALGORITHMS,
|
|
|
|
recentAlgsString)
|
2015-05-20 19:33:47 +02:00
|
|
|
else:
|
|
|
|
if isinstance(msg, list):
|
|
|
|
msg = '\n'.join([m for m in msg])
|
|
|
|
msgtypes = {ProcessingLog.LOG_ERROR: QgsMessageLog.CRITICAL,
|
|
|
|
ProcessingLog.LOG_INFO: QgsMessageLog.INFO,
|
2015-08-22 14:29:41 +02:00
|
|
|
ProcessingLog.LOG_WARNING: QgsMessageLog.WARNING, }
|
2015-05-20 19:33:47 +02:00
|
|
|
QgsMessageLog.logMessage(msg, "Processing", msgtypes[msgtype])
|
2012-09-15 18:25:25 +03:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def getLogEntries():
|
2013-10-01 20:52:22 +03:00
|
|
|
entries = {}
|
|
|
|
errors = []
|
|
|
|
algorithms = []
|
|
|
|
warnings = []
|
|
|
|
info = []
|
2013-08-12 20:44:27 +02:00
|
|
|
lines = tail(ProcessingLog.logFilename())
|
2013-02-17 23:00:04 +01:00
|
|
|
for line in lines:
|
2013-10-01 20:52:22 +03:00
|
|
|
line = line.strip('\n').strip()
|
|
|
|
tokens = line.split('|')
|
|
|
|
text = ''
|
2012-09-15 18:25:25 +03:00
|
|
|
for i in range(2, len(tokens)):
|
2013-10-01 20:52:22 +03:00
|
|
|
text += tokens[i] + '|'
|
2013-08-12 20:44:27 +02:00
|
|
|
if line.startswith(ProcessingLog.LOG_ERROR):
|
2012-09-15 18:25:25 +03:00
|
|
|
errors.append(LogEntry(tokens[1], text))
|
2013-08-12 20:44:27 +02:00
|
|
|
elif line.startswith(ProcessingLog.LOG_ALGORITHM):
|
2012-09-15 18:25:25 +03:00
|
|
|
algorithms.append(LogEntry(tokens[1], tokens[2]))
|
2013-08-12 20:44:27 +02:00
|
|
|
elif line.startswith(ProcessingLog.LOG_WARNING):
|
2012-09-15 18:25:25 +03:00
|
|
|
warnings.append(LogEntry(tokens[1], text))
|
2013-08-12 20:44:27 +02:00
|
|
|
elif line.startswith(ProcessingLog.LOG_INFO):
|
2012-09-15 18:25:25 +03:00
|
|
|
info.append(LogEntry(tokens[1], text))
|
2013-05-24 00:38:29 +02:00
|
|
|
|
2013-08-12 20:44:27 +02:00
|
|
|
entries[ProcessingLog.LOG_ALGORITHM] = algorithms
|
2012-09-15 18:25:25 +03:00
|
|
|
return entries
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def getRecentAlgorithms():
|
2013-10-01 20:52:22 +03:00
|
|
|
recentAlgsSetting = ProcessingConfig.getSetting(
|
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
|
|
|
ProcessingConfig.RECENT_ALGORITHMS)
|
2012-09-15 18:25:25 +03:00
|
|
|
try:
|
2013-08-12 20:44:27 +02:00
|
|
|
ProcessingLog.recentAlgs = recentAlgsSetting.split(';')
|
2012-09-15 18:25:25 +03:00
|
|
|
except:
|
|
|
|
pass
|
2013-08-12 20:44:27 +02:00
|
|
|
return ProcessingLog.recentAlgs
|
2012-09-15 18:25:25 +03:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def clearLog():
|
2013-08-12 20:44:27 +02:00
|
|
|
os.unlink(ProcessingLog.logFilename())
|
|
|
|
ProcessingLog.startLogging()
|
2012-09-15 18:25:25 +03:00
|
|
|
|
2014-09-14 15:53:12 +03:00
|
|
|
@staticmethod
|
|
|
|
def saveLog(fileName):
|
|
|
|
entries = ProcessingLog.getLogEntries()
|
|
|
|
with codecs.open(fileName, 'w', encoding='utf-8') as f:
|
|
|
|
for k, v in entries.iteritems():
|
|
|
|
for entry in v:
|
|
|
|
f.write('%s|%s|%s\n' % (k, entry.date, entry.text))
|
|
|
|
|
2013-10-01 20:52:22 +03:00
|
|
|
|
|
|
|
class LogEntry:
|
|
|
|
|
2012-09-15 18:25:25 +03:00
|
|
|
def __init__(self, date, text):
|
|
|
|
self.date = date
|
|
|
|
self.text = text
|
2013-02-28 22:08:32 +01:00
|
|
|
|
2013-10-01 20:52:22 +03:00
|
|
|
"""
|
|
|
|
***************************************************************************
|
|
|
|
This code has been take from pytailer
|
|
|
|
http://code.google.com/p/pytailer/
|
|
|
|
|
|
|
|
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.
|
|
|
|
***************************************************************************
|
|
|
|
"""
|
2013-02-17 23:00:04 +01:00
|
|
|
|
|
|
|
|
|
|
|
class Tailer(object):
|
2015-08-22 14:29:41 +02:00
|
|
|
|
2013-10-01 20:52:22 +03:00
|
|
|
"""Implements tailing and heading functionality like GNU tail and
|
|
|
|
head commands.
|
2013-02-17 23:00:04 +01:00
|
|
|
"""
|
|
|
|
line_terminators = ('\r\n', '\n', '\r')
|
|
|
|
|
|
|
|
def __init__(self, filename, read_size=1024, end=False):
|
|
|
|
self.read_size = read_size
|
2013-10-01 20:52:22 +03:00
|
|
|
self.file = codecs.open(filename, encoding='utf-8')
|
2013-02-17 23:00:04 +01:00
|
|
|
self.start_pos = self.file.tell()
|
|
|
|
if end:
|
|
|
|
self.seek_end()
|
2013-02-28 22:08:32 +01:00
|
|
|
|
2013-02-17 23:00:04 +01:00
|
|
|
def splitlines(self, data):
|
|
|
|
return re.split('|'.join(self.line_terminators), data)
|
|
|
|
|
|
|
|
def seek_end(self):
|
|
|
|
self.seek(0, 2)
|
|
|
|
|
|
|
|
def seek(self, pos, whence=0):
|
|
|
|
self.file.seek(pos, whence)
|
|
|
|
|
|
|
|
def read(self, read_size=None):
|
|
|
|
if read_size:
|
|
|
|
read_str = self.file.read(read_size)
|
|
|
|
else:
|
|
|
|
read_str = self.file.read()
|
|
|
|
|
2013-10-01 20:52:22 +03:00
|
|
|
return (len(read_str), read_str)
|
2013-02-17 23:00:04 +01:00
|
|
|
|
|
|
|
def seek_line(self):
|
2013-10-01 20:52:22 +03:00
|
|
|
"""Searches backwards from the current file position for a
|
|
|
|
line terminator and seeks to the charachter after it.
|
2013-02-17 23:00:04 +01:00
|
|
|
"""
|
|
|
|
pos = end_pos = self.file.tell()
|
|
|
|
|
|
|
|
read_size = self.read_size
|
|
|
|
if pos > read_size:
|
|
|
|
pos -= read_size
|
|
|
|
else:
|
|
|
|
pos = 0
|
|
|
|
read_size = end_pos
|
|
|
|
|
|
|
|
self.seek(pos)
|
|
|
|
|
2013-10-01 20:52:22 +03:00
|
|
|
(bytes_read, read_str) = self.read(read_size)
|
2013-02-17 23:00:04 +01:00
|
|
|
|
|
|
|
if bytes_read and read_str[-1] in self.line_terminators:
|
2013-10-01 20:52:22 +03:00
|
|
|
# The last charachter is a line terminator, don't count
|
|
|
|
# this one.
|
2013-02-17 23:00:04 +01:00
|
|
|
bytes_read -= 1
|
|
|
|
|
|
|
|
if read_str[-2:] == '\r\n' and '\r\n' in self.line_terminators:
|
2013-10-01 20:52:22 +03:00
|
|
|
# found CRLF
|
2013-02-17 23:00:04 +01:00
|
|
|
bytes_read -= 1
|
|
|
|
|
2013-02-28 22:08:32 +01:00
|
|
|
while bytes_read > 0:
|
2013-02-17 23:00:04 +01:00
|
|
|
# Scan backward, counting the newlines in this bufferfull
|
|
|
|
i = bytes_read - 1
|
|
|
|
while i >= 0:
|
|
|
|
if read_str[i] in self.line_terminators:
|
|
|
|
self.seek(pos + i + 1)
|
|
|
|
return self.file.tell()
|
|
|
|
i -= 1
|
|
|
|
|
|
|
|
if pos == 0 or pos - self.read_size < 0:
|
|
|
|
# Not enought lines in the buffer, send the whole file
|
|
|
|
self.seek(0)
|
|
|
|
return None
|
|
|
|
|
|
|
|
pos -= self.read_size
|
|
|
|
self.seek(pos)
|
|
|
|
|
2013-10-01 20:52:22 +03:00
|
|
|
(bytes_read, read_str) = self.read(self.read_size)
|
2013-02-17 23:00:04 +01:00
|
|
|
|
|
|
|
return None
|
2013-02-28 22:08:32 +01:00
|
|
|
|
2013-02-17 23:00:04 +01:00
|
|
|
def tail(self, lines=10):
|
2013-10-01 20:52:22 +03:00
|
|
|
"""Return the last lines of the file.
|
2013-02-17 23:00:04 +01:00
|
|
|
"""
|
|
|
|
self.seek_end()
|
|
|
|
end_pos = self.file.tell()
|
|
|
|
|
|
|
|
for i in xrange(lines):
|
|
|
|
if not self.seek_line():
|
|
|
|
break
|
|
|
|
|
|
|
|
data = self.file.read(end_pos - self.file.tell() - 1)
|
|
|
|
if data:
|
|
|
|
return self.splitlines(data)
|
|
|
|
else:
|
|
|
|
return []
|
2013-02-28 22:08:32 +01:00
|
|
|
|
2013-02-17 23:00:04 +01:00
|
|
|
def __iter__(self):
|
|
|
|
return self.follow()
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self.file.close()
|
|
|
|
|
2013-10-01 20:52:22 +03:00
|
|
|
|
2013-02-17 23:00:04 +01:00
|
|
|
def tail(file, lines=200):
|
|
|
|
return Tailer(file).tail(lines)
|