Revert logging functions

Fix access logger for tornado
pull/945/head
Ozzieisaacs 6 years ago
parent 8e4539cf8e
commit 26949970d8

@ -88,13 +88,14 @@ from .server import server
Server = server() Server = server()
babel = Babel() babel = Babel()
log = logger.create()
def create_app(): def create_app():
app.wsgi_app = ReverseProxied(app.wsgi_app) app.wsgi_app = ReverseProxied(app.wsgi_app)
cache_buster.init_cache_busting(app) cache_buster.init_cache_busting(app)
logger.info('Starting Calibre Web...') log.info('Starting Calibre Web...')
Principal(app) Principal(app)
lm.init_app(app) lm.init_app(app)
app.secret_key = os.getenv('SECRET_KEY', 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT') app.secret_key = os.getenv('SECRET_KEY', 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT')
@ -118,7 +119,7 @@ def get_locale():
try: try:
preferred.append(str(LC.parse(x.replace('-', '_')))) preferred.append(str(LC.parse(x.replace('-', '_'))))
except (UnknownLocaleError, ValueError) as e: except (UnknownLocaleError, ValueError) as e:
logger.warning('Could not parse locale "%s": %s', x, e) log.warning('Could not parse locale "%s": %s', x, e)
preferred.append('en') preferred.append('en')
return negotiate_locale(preferred, translations) return negotiate_locale(preferred, translations)

@ -76,7 +76,7 @@ except ImportError:
feature_support['gdrive'] = gdrive_support feature_support['gdrive'] = gdrive_support
admi = Blueprint('admin', __name__) admi = Blueprint('admin', __name__)
# log = logger.create() log = logger.create()
@admi.route("/admin") @admi.route("/admin")
@ -220,7 +220,7 @@ def view_configuration():
# stop Server # stop Server
Server.setRestartTyp(True) Server.setRestartTyp(True)
Server.stopServer() Server.stopServer()
logger.info('Reboot required, restarting') log.info('Reboot required, restarting')
readColumn = db.session.query(db.Custom_Columns)\ readColumn = db.session.query(db.Custom_Columns)\
.filter(and_(db.Custom_Columns.datatype == 'bool',db.Custom_Columns.mark_for_delete == 0)).all() .filter(and_(db.Custom_Columns.datatype == 'bool',db.Custom_Columns.mark_for_delete == 0)).all()
return render_title_template("config_view_edit.html", conf=config, readColumns=readColumn, return render_title_template("config_view_edit.html", conf=config, readColumns=readColumn,
@ -518,7 +518,7 @@ def configuration_helper(origin):
# stop Server # stop Server
Server.setRestartTyp(True) Server.setRestartTyp(True)
Server.stopServer() Server.stopServer()
logger.info('Reboot required, restarting') log.info('Reboot required, restarting')
if origin: if origin:
success = True success = True
if is_gdrive_ready() and feature_support['gdrive'] is True: # and config.config_use_google_drive == True: if is_gdrive_ready() and feature_support['gdrive'] is True: # and config.config_use_google_drive == True:

@ -24,7 +24,7 @@ import hashlib
from . import logger from . import logger
# log = logger.create() log = logger.create()
def init_cache_busting(app): def init_cache_busting(app):
@ -40,7 +40,7 @@ def init_cache_busting(app):
hash_table = {} # map of file hashes hash_table = {} # map of file hashes
logger.debug('Computing cache-busting values...') log.debug('Computing cache-busting values...')
# compute file hashes # compute file hashes
for dirpath, __, filenames in os.walk(static_folder): for dirpath, __, filenames in os.walk(static_folder):
for filename in filenames: for filename in filenames:
@ -53,7 +53,7 @@ def init_cache_busting(app):
file_path = rooted_filename.replace(static_folder, "") file_path = rooted_filename.replace(static_folder, "")
file_path = file_path.replace("\\", "/") # Convert Windows path to web path file_path = file_path.replace("\\", "/") # Convert Windows path to web path
hash_table[file_path] = file_hash hash_table[file_path] = file_hash
logger.debug('Finished computing cache-busting values') log.debug('Finished computing cache-busting values')
def bust_filename(filename): def bust_filename(filename):
return hash_table.get(filename, "") return hash_table.get(filename, "")

@ -24,14 +24,14 @@ from . import logger, isoLanguages
from .constants import BookMeta from .constants import BookMeta
# log = logger.create() log = logger.create()
try: try:
from comicapi.comicarchive import ComicArchive, MetaDataStyle from comicapi.comicarchive import ComicArchive, MetaDataStyle
use_comic_meta = True use_comic_meta = True
except ImportError as e: except ImportError as e:
logger.warning('cannot import comicapi, extracting comic metadata will not work: %s', e) log.warning('cannot import comicapi, extracting comic metadata will not work: %s', e)
import zipfile import zipfile
import tarfile import tarfile
use_comic_meta = False use_comic_meta = False

@ -39,7 +39,7 @@ from .web import login_required_if_no_ano, render_title_template, edit_required,
editbook = Blueprint('editbook', __name__) editbook = Blueprint('editbook', __name__)
# log = logger.create() log = logger.create()
# Modifies different Database objects, first check if elements have to be added to database, than check # Modifies different Database objects, first check if elements have to be added to database, than check
@ -198,7 +198,7 @@ def delete_book(book_id, book_format):
db.session.commit() db.session.commit()
else: else:
# book not found # book not found
logger.error('Book with id "%s" could not be deleted: not found', book_id) log.error('Book with id "%s" could not be deleted: not found', book_id)
if book_format: if book_format:
return redirect(url_for('editbook.edit_book', book_id=book_id)) return redirect(url_for('editbook.edit_book', book_id=book_id))
else: else:
@ -237,7 +237,7 @@ def render_edit_book(book_id):
try: try:
allowed_conversion_formats.remove(file.format.lower()) allowed_conversion_formats.remove(file.format.lower())
except Exception: except Exception:
logger.warning('%s already removed from list.', file.format.lower()) log.warning('%s already removed from list.', file.format.lower())
return render_title_template('book_edit.html', book=book, authors=author_names, cc=cc, return render_title_template('book_edit.html', book=book, authors=author_names, cc=cc,
title=_(u"edit metadata"), page="editbook", title=_(u"edit metadata"), page="editbook",
@ -349,7 +349,7 @@ def upload_single_file(request, book, book_id):
# Format entry already exists, no need to update the database # Format entry already exists, no need to update the database
if is_format: if is_format:
logger.warning('Book format %s already existing', file_ext.upper()) log.warning('Book format %s already existing', file_ext.upper())
else: else:
db_format = db.Data(book_id, file_ext.upper(), file_size, file_name) db_format = db.Data(book_id, file_ext.upper(), file_size, file_name)
db.session.add(db_format) db.session.add(db_format)
@ -492,7 +492,7 @@ def edit_book(book_id):
res = list(language_table[get_locale()].keys())[invers_lang_table.index(lang)] res = list(language_table[get_locale()].keys())[invers_lang_table.index(lang)]
input_l.append(res) input_l.append(res)
except ValueError: except ValueError:
logger.error('%s is not a valid language', lang) log.error('%s is not a valid language', lang)
flash(_(u"%(langname)s is not a valid language", langname=lang), category="error") flash(_(u"%(langname)s is not a valid language", langname=lang), category="error")
modify_database_object(input_l, book.languages, db.Languages, db.session, 'languages') modify_database_object(input_l, book.languages, db.Languages, db.session, 'languages')
@ -531,7 +531,7 @@ def edit_book(book_id):
flash(error, category="error") flash(error, category="error")
return render_edit_book(book_id) return render_edit_book(book_id)
except Exception as e: except Exception as e:
logger.exception(e) log.exception(e)
db.session.rollback() db.session.rollback()
flash(_("Error editing book, please check logfile for details"), category="error") flash(_("Error editing book, please check logfile for details"), category="error")
return redirect(url_for('web.show_book', book_id=book.id)) return redirect(url_for('web.show_book', book_id=book.id))
@ -703,7 +703,7 @@ def convert_bookformat(book_id):
flash(_(u"Source or destination format for conversion missing"), category="error") flash(_(u"Source or destination format for conversion missing"), category="error")
return redirect(request.environ["HTTP_REFERER"]) return redirect(request.environ["HTTP_REFERER"])
logger.info('converting: book id: %s from: %s to: %s', book_id, book_format_from, book_format_to) log.info('converting: book id: %s from: %s to: %s', book_id, book_format_from, book_format_to)
rtn = helper.convert_book_format(book_id, config.config_calibre_dir, book_format_from.upper(), rtn = helper.convert_book_format(book_id, config.config_calibre_dir, book_format_from.upper(),
book_format_to.upper(), current_user.nickname) book_format_to.upper(), current_user.nickname)

@ -44,7 +44,7 @@ from .web import admin_required
gdrive = Blueprint('gdrive', __name__) gdrive = Blueprint('gdrive', __name__)
# log = logger.create() log = logger.create()
current_milli_time = lambda: int(round(time() * 1000)) current_milli_time = lambda: int(round(time() * 1000))
@ -74,7 +74,7 @@ def google_drive_callback():
with open(gdriveutils.CREDENTIALS, 'w') as f: with open(gdriveutils.CREDENTIALS, 'w') as f:
f.write(credentials.to_json()) f.write(credentials.to_json())
except ValueError as error: except ValueError as error:
logger.error(error) log.error(error)
return redirect(url_for('admin.configuration')) return redirect(url_for('admin.configuration'))
@ -131,7 +131,7 @@ def revoke_watch_gdrive():
@gdrive.route("/gdrive/watch/callback", methods=['GET', 'POST']) @gdrive.route("/gdrive/watch/callback", methods=['GET', 'POST'])
def on_received_watch_confirmation(): def on_received_watch_confirmation():
logger.debug('%r', request.headers) log.debug('%r', request.headers)
if request.headers.get('X-Goog-Channel-Token') == gdrive_watch_callback_token \ if request.headers.get('X-Goog-Channel-Token') == gdrive_watch_callback_token \
and request.headers.get('X-Goog-Resource-State') == 'change' \ and request.headers.get('X-Goog-Resource-State') == 'change' \
and request.data: and request.data:
@ -139,26 +139,26 @@ def on_received_watch_confirmation():
data = request.data data = request.data
def updateMetaData(): def updateMetaData():
logger.info('Change received from gdrive') log.info('Change received from gdrive')
logger.debug('%r', data) log.debug('%r', data)
try: try:
j = json.loads(data) j = json.loads(data)
logger.info('Getting change details') log.info('Getting change details')
response = gdriveutils.getChangeById(gdriveutils.Gdrive.Instance().drive, j['id']) response = gdriveutils.getChangeById(gdriveutils.Gdrive.Instance().drive, j['id'])
logger.debug('%r', response) log.debug('%r', response)
if response: if response:
dbpath = os.path.join(config.config_calibre_dir, "metadata.db") dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
if not response['deleted'] and response['file']['title'] == 'metadata.db' and response['file']['md5Checksum'] != hashlib.md5(dbpath): if not response['deleted'] and response['file']['title'] == 'metadata.db' and response['file']['md5Checksum'] != hashlib.md5(dbpath):
tmpDir = tempfile.gettempdir() tmpDir = tempfile.gettempdir()
logger.info('Database file updated') log.info('Database file updated')
copyfile(dbpath, os.path.join(tmpDir, "metadata.db_" + str(current_milli_time()))) copyfile(dbpath, os.path.join(tmpDir, "metadata.db_" + str(current_milli_time())))
logger.info('Backing up existing and downloading updated metadata.db') log.info('Backing up existing and downloading updated metadata.db')
gdriveutils.downloadFile(None, "metadata.db", os.path.join(tmpDir, "tmp_metadata.db")) gdriveutils.downloadFile(None, "metadata.db", os.path.join(tmpDir, "tmp_metadata.db"))
logger.info('Setting up new DB') log.info('Setting up new DB')
# prevent error on windows, as os.rename does on exisiting files # prevent error on windows, as os.rename does on exisiting files
move(os.path.join(tmpDir, "tmp_metadata.db"), dbpath) move(os.path.join(tmpDir, "tmp_metadata.db"), dbpath)
db.setup_db() db.setup_db()
except Exception as e: except Exception as e:
logger.exception(e) log.exception(e)
updateMetaData() updateMetaData()
return '' return ''

@ -45,7 +45,7 @@ SETTINGS_YAML = os.path.join(_BASE_DIR, 'settings.yaml')
CREDENTIALS = os.path.join(_BASE_DIR, 'gdrive_credentials') CREDENTIALS = os.path.join(_BASE_DIR, 'gdrive_credentials')
CLIENT_SECRETS = os.path.join(_BASE_DIR, 'client_secrets.json') CLIENT_SECRETS = os.path.join(_BASE_DIR, 'client_secrets.json')
# log = logger.create() log = logger.create()
class Singleton: class Singleton:
@ -169,9 +169,9 @@ def getDrive(drive=None, gauth=None):
try: try:
gauth.Refresh() gauth.Refresh()
except RefreshError as e: except RefreshError as e:
logger.error("Google Drive error: %s", e) log.error("Google Drive error: %s", e)
except Exception as e: except Exception as e:
logger.exception(e) log.exception(e)
else: else:
# Initialize the saved creds # Initialize the saved creds
gauth.Authorize() gauth.Authorize()
@ -181,7 +181,7 @@ def getDrive(drive=None, gauth=None):
try: try:
drive.auth.Refresh() drive.auth.Refresh()
except RefreshError as e: except RefreshError as e:
logger.error("Google Drive error: %s", e) log.error("Google Drive error: %s", e)
return drive return drive
def listRootFolders(): def listRootFolders():
@ -218,7 +218,7 @@ def getEbooksFolderId(drive=None):
try: try:
gDriveId.gdrive_id = getEbooksFolder(drive)['id'] gDriveId.gdrive_id = getEbooksFolder(drive)['id']
except Exception: except Exception:
logger.error('Error gDrive, root ID not found') log.error('Error gDrive, root ID not found')
gDriveId.path = '/' gDriveId.path = '/'
session.merge(gDriveId) session.merge(gDriveId)
session.commit() session.commit()
@ -458,10 +458,10 @@ def getChangeById (drive, change_id):
change = drive.auth.service.changes().get(changeId=change_id).execute() change = drive.auth.service.changes().get(changeId=change_id).execute()
return change return change
except (errors.HttpError) as error: except (errors.HttpError) as error:
logger.error(error) log.error(error)
return None return None
except Exception as e: except Exception as e:
logger.error(e) log.error(e)
return None return None
@ -531,6 +531,6 @@ def do_gdrive_download(df, headers):
if resp.status == 206: if resp.status == 206:
yield content yield content
else: else:
logger.warning('An error occurred: %s', resp) log.warning('An error occurred: %s', resp)
return return
return Response(stream_with_context(stream()), headers=headers) return Response(stream_with_context(stream()), headers=headers)

@ -75,7 +75,7 @@ from .worker import STAT_WAITING, STAT_FAIL, STAT_STARTED, STAT_FINISH_SUCCESS
from .worker import TASK_EMAIL, TASK_CONVERT, TASK_UPLOAD, TASK_CONVERT_ANY from .worker import TASK_EMAIL, TASK_CONVERT, TASK_UPLOAD, TASK_CONVERT_ANY
# log = logger.create() log = logger.create()
def update_download(book_id, user_id): def update_download(book_id, user_id):
@ -92,7 +92,7 @@ def convert_book_format(book_id, calibrepath, old_book_format, new_book_format,
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == old_book_format).first() data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == old_book_format).first()
if not data: if not data:
error_message = _(u"%(format)s format not found for book id: %(book)d", format=old_book_format, book=book_id) error_message = _(u"%(format)s format not found for book id: %(book)d", format=old_book_format, book=book_id)
logger.error("convert_book_format: %s", error_message) log.error("convert_book_format: %s", error_message)
return error_message return error_message
if config.config_use_google_drive: if config.config_use_google_drive:
df = gd.getFileFromEbooksFolder(book.path, data.name + "." + old_book_format.lower()) df = gd.getFileFromEbooksFolder(book.path, data.name + "." + old_book_format.lower())
@ -186,7 +186,7 @@ def check_send_to_kindle(entry):
'text':_('Convert %(orig)s to %(format)s and send to Kindle',orig='Epub',format='Azw3')})''' 'text':_('Convert %(orig)s to %(format)s and send to Kindle',orig='Epub',format='Azw3')})'''
return bookformats return bookformats
else: else:
logger.error(u'Cannot find book entry %d', entry.id) log.error(u'Cannot find book entry %d', entry.id)
return None return None
@ -272,7 +272,7 @@ def get_sorted_author(value):
else: else:
value2 = value value2 = value
except Exception as ex: except Exception as ex:
logger.error("Sorting author %s failed: %s", value, ex) log.error("Sorting author %s failed: %s", value, ex)
value2 = value value2 = value
return value2 return value2
@ -289,12 +289,12 @@ def delete_book_file(book, calibrepath, book_format=None):
else: else:
if os.path.isdir(path): if os.path.isdir(path):
if len(next(os.walk(path))[1]): if len(next(os.walk(path))[1]):
logger.error("Deleting book %s failed, path has subfolders: %s", book.id, book.path) log.error("Deleting book %s failed, path has subfolders: %s", book.id, book.path)
return False return False
shutil.rmtree(path, ignore_errors=True) shutil.rmtree(path, ignore_errors=True)
return True return True
else: else:
logger.error("Deleting book %s failed, book path not valid: %s", book.id, book.path) log.error("Deleting book %s failed, book path not valid: %s", book.id, book.path)
return False return False
@ -317,7 +317,7 @@ def update_dir_structure_file(book_id, calibrepath, first_author):
if not os.path.exists(new_title_path): if not os.path.exists(new_title_path):
os.renames(path, new_title_path) os.renames(path, new_title_path)
else: else:
logger.info("Copying title: %s into existing: %s", path, new_title_path) log.info("Copying title: %s into existing: %s", path, new_title_path)
for dir_name, __, file_list in os.walk(path): for dir_name, __, file_list in os.walk(path):
for file in file_list: for file in file_list:
os.renames(os.path.join(dir_name, file), os.renames(os.path.join(dir_name, file),
@ -325,8 +325,8 @@ def update_dir_structure_file(book_id, calibrepath, first_author):
path = new_title_path path = new_title_path
localbook.path = localbook.path.split('/')[0] + '/' + new_titledir localbook.path = localbook.path.split('/')[0] + '/' + new_titledir
except OSError as ex: except OSError as ex:
logger.error("Rename title from: %s to %s: %s", path, new_title_path, ex) log.error("Rename title from: %s to %s: %s", path, new_title_path, ex)
logger.debug(ex, exc_info=True) log.debug(ex, exc_info=True)
return _("Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s", return _("Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
src=path, dest=new_title_path, error=str(ex)) src=path, dest=new_title_path, error=str(ex))
if authordir != new_authordir: if authordir != new_authordir:
@ -335,8 +335,8 @@ def update_dir_structure_file(book_id, calibrepath, first_author):
os.renames(path, new_author_path) os.renames(path, new_author_path)
localbook.path = new_authordir + '/' + localbook.path.split('/')[1] localbook.path = new_authordir + '/' + localbook.path.split('/')[1]
except OSError as ex: except OSError as ex:
logger.error("Rename author from: %s to %s: %s", path, new_author_path, ex) log.error("Rename author from: %s to %s: %s", path, new_author_path, ex)
logger.debug(ex, exc_info=True) log.debug(ex, exc_info=True)
return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s", return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
src=path, dest=new_author_path, error=str(ex)) src=path, dest=new_author_path, error=str(ex))
# Rename all files from old names to new names # Rename all files from old names to new names
@ -349,8 +349,8 @@ def update_dir_structure_file(book_id, calibrepath, first_author):
os.path.join(path_name, new_name + '.' + file_format.format.lower())) os.path.join(path_name, new_name + '.' + file_format.format.lower()))
file_format.name = new_name file_format.name = new_name
except OSError as ex: except OSError as ex:
logger.error("Rename file in path %s to %s: %s", path, new_name, ex) log.error("Rename file in path %s to %s: %s", path, new_name, ex)
logger.debug(ex, exc_info=True) log.debug(ex, exc_info=True)
return _("Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s", return _("Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s",
src=path, dest=new_name, error=str(ex)) src=path, dest=new_name, error=str(ex))
return False return False
@ -454,10 +454,10 @@ def get_book_cover(book_id):
if path: if path:
return redirect(path) return redirect(path)
else: else:
logger.error('%s/cover.jpg not found on Google Drive', book.path) log.error('%s/cover.jpg not found on Google Drive', book.path)
return send_from_directory(_STATIC_DIR, "generic_cover.jpg") return send_from_directory(_STATIC_DIR, "generic_cover.jpg")
except Exception as e: except Exception as e:
logger.exception(e) log.exception(e)
# traceback.print_exc() # traceback.print_exc()
return send_from_directory(_STATIC_DIR,"generic_cover.jpg") return send_from_directory(_STATIC_DIR,"generic_cover.jpg")
else: else:
@ -487,15 +487,15 @@ def save_cover_from_filestorage(filepath, saved_filename, img):
try: try:
os.makedirs(filepath) os.makedirs(filepath)
except OSError: except OSError:
logger.error(u"Failed to create path for cover") log.error(u"Failed to create path for cover")
return False return False
try: try:
img.save(os.path.join(filepath, saved_filename)) img.save(os.path.join(filepath, saved_filename))
except IOError: except IOError:
logger.error(u"Cover-file is not a valid image file") log.error(u"Cover-file is not a valid image file")
return False return False
except OSError: except OSError:
logger.error(u"Failed to store cover-file") log.error(u"Failed to store cover-file")
return False return False
return True return True
@ -506,7 +506,7 @@ def save_cover(img, book_path):
if use_PIL: if use_PIL:
if content_type not in ('image/jpeg', 'image/png', 'image/webp'): if content_type not in ('image/jpeg', 'image/png', 'image/webp'):
logger.error("Only jpg/jpeg/png/webp files are supported as coverfile") log.error("Only jpg/jpeg/png/webp files are supported as coverfile")
return False return False
# convert to jpg because calibre only supports jpg # convert to jpg because calibre only supports jpg
if content_type in ('image/png', 'image/webp'): if content_type in ('image/png', 'image/webp'):
@ -520,7 +520,7 @@ def save_cover(img, book_path):
img._content = tmp_bytesio.getvalue() img._content = tmp_bytesio.getvalue()
else: else:
if content_type not in ('image/jpeg'): if content_type not in ('image/jpeg'):
logger.error("Only jpg/jpeg files are supported as coverfile") log.error("Only jpg/jpeg files are supported as coverfile")
return False return False
if ub.config.config_use_google_drive: if ub.config.config_use_google_drive:
@ -528,7 +528,7 @@ def save_cover(img, book_path):
if save_cover_from_filestorage(tmpDir, "uploaded_cover.jpg", img) is True: if save_cover_from_filestorage(tmpDir, "uploaded_cover.jpg", img) is True:
gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg'), gd.uploadFileToEbooksFolder(os.path.join(book_path, 'cover.jpg'),
os.path.join(tmpDir, "uploaded_cover.jpg")) os.path.join(tmpDir, "uploaded_cover.jpg"))
logger.info("Cover is saved on Google Drive") log.info("Cover is saved on Google Drive")
return True return True
else: else:
return False return False
@ -541,7 +541,7 @@ def do_download_file(book, book_format, data, headers):
if config.config_use_google_drive: if config.config_use_google_drive:
startTime = time.time() startTime = time.time()
df = gd.getFileFromEbooksFolder(book.path, data.name + "." + book_format) df = gd.getFileFromEbooksFolder(book.path, data.name + "." + book_format)
logger.debug('%s', time.time() - startTime) log.debug('%s', time.time() - startTime)
if df: if df:
return gd.do_gdrive_download(df, headers) return gd.do_gdrive_download(df, headers)
else: else:
@ -550,7 +550,7 @@ def do_download_file(book, book_format, data, headers):
filename = os.path.join(config.config_calibre_dir, book.path) filename = os.path.join(config.config_calibre_dir, book.path)
if not os.path.isfile(os.path.join(filename, data.name + "." + book_format)): if not os.path.isfile(os.path.join(filename, data.name + "." + book_format)):
# ToDo: improve error handling # ToDo: improve error handling
logger.error('File not found: %s', os.path.join(filename, data.name + "." + book_format)) log.error('File not found: %s', os.path.join(filename, data.name + "." + book_format))
response = make_response(send_from_directory(filename, data.name + "." + book_format)) response = make_response(send_from_directory(filename, data.name + "." + book_format))
response.headers = headers response.headers = headers
return response return response
@ -575,7 +575,7 @@ def check_unrar(unrarLocation):
version = value.group(1) version = value.group(1)
except OSError as e: except OSError as e:
error = True error = True
logger.exception(e) log.exception(e)
version =_(u'Error excecuting UnRar') version =_(u'Error excecuting UnRar')
else: else:
version = _(u'Unrar binary file not found') version = _(u'Unrar binary file not found')

@ -37,7 +37,7 @@ from . import logger
jinjia = Blueprint('jinjia', __name__) jinjia = Blueprint('jinjia', __name__)
# log = logger.create() log = logger.create()
# pagination links in jinja # pagination links in jinja
@ -85,7 +85,7 @@ def formatdate_filter(val):
formatdate = datetime.datetime.strptime(conformed_timestamp[:15], "%Y%m%d %H%M%S") formatdate = datetime.datetime.strptime(conformed_timestamp[:15], "%Y%m%d %H%M%S")
return format_date(formatdate, format='medium', locale=get_locale()) return format_date(formatdate, format='medium', locale=get_locale())
except AttributeError as e: except AttributeError as e:
logger.error('Babel error: %s, Current user locale: %s, Current User: %s', e, current_user.locale, current_user.nickname) log.error('Babel error: %s, Current user locale: %s, Current User: %s', e, current_user.locale, current_user.nickname)
return formatdate return formatdate
@jinjia.app_template_filter('formatdateinput') @jinjia.app_template_filter('formatdateinput')

@ -25,7 +25,9 @@ from logging.handlers import RotatingFileHandler
from .constants import BASE_DIR as _BASE_DIR from .constants import BASE_DIR as _BASE_DIR
ACCESS_FORMATTER = Formatter("%(message)s") ACCESS_FORMATTER_GEVENT = Formatter("%(message)s")
ACCESS_FORMATTER_TORNADO = Formatter("[%(asctime)s] %(message)s")
FORMATTER = Formatter("[%(asctime)s] %(levelname)5s {%(name)s:%(lineno)d} %(message)s") FORMATTER = Formatter("[%(asctime)s] %(levelname)5s {%(name)s:%(lineno)d} %(message)s")
DEFAULT_LOG_LEVEL = logging.INFO DEFAULT_LOG_LEVEL = logging.INFO
DEFAULT_LOG_FILE = os.path.join(_BASE_DIR, "calibre-web.log") DEFAULT_LOG_FILE = os.path.join(_BASE_DIR, "calibre-web.log")
@ -37,38 +39,12 @@ logging.addLevelName(logging.WARNING, "WARN")
logging.addLevelName(logging.CRITICAL, "CRIT") logging.addLevelName(logging.CRITICAL, "CRIT")
def info(msg, *args, **kwargs):
create(2).info(msg, *args, **kwargs)
def warning(msg, *args, **kwargs):
create(2).warning(msg, *args, **kwargs)
def error(msg, *args, **kwargs):
create(2).error(msg, *args, **kwargs)
def critical(msg, *args, **kwargs):
create(2).critical(msg, *args, **kwargs)
def exception(msg, *args, **kwargs):
create(2).exception(msg, *args, **kwargs)
def debug(msg, *args, **kwargs):
create(2).debug(msg, *args, **kwargs)
def get(name=None): def get(name=None):
val = logging.getLogger("general") return logging.getLogger(name)
val.name = name
return val
def create(ini=1): def create():
parent_frame = inspect.stack(0)[ini] parent_frame = inspect.stack(0)[1]
if hasattr(parent_frame, 'frame'): if hasattr(parent_frame, 'frame'):
parent_frame = parent_frame.frame parent_frame = parent_frame.frame
else: else:
@ -77,8 +53,8 @@ def create(ini=1):
return get(parent_module.__name__) return get(parent_module.__name__)
def is_debug_enabled(logger): def is_debug_enabled():
return logging.getLogger(logger).level <= logging.DEBUG return logging.root.level <= logging.DEBUG
def is_info_enabled(logger): def is_info_enabled(logger):
return logging.getLogger(logger).level <= logging.INFO return logging.getLogger(logger).level <= logging.INFO
@ -97,12 +73,15 @@ def is_valid_logfile(file_path):
return (not log_dir) or os.path.isdir(log_dir) return (not log_dir) or os.path.isdir(log_dir)
def setup(log_file, logger, log_level=None): def setup(log_file, log_level=None, logger=None):
if logger == "general": if logger != "access" and logger != "tornado.access":
formatter = FORMATTER formatter = FORMATTER
default_file = DEFAULT_LOG_FILE default_file = DEFAULT_LOG_FILE
else: else:
formatter = ACCESS_FORMATTER if logger == "tornado.access":
formatter = ACCESS_FORMATTER_TORNADO
else:
formatter = ACCESS_FORMATTER_GEVENT
default_file = DEFAULT_ACCESS_LOG default_file = DEFAULT_ACCESS_LOG
if log_file: if log_file:
if not os.path.dirname(log_file): if not os.path.dirname(log_file):
@ -113,7 +92,11 @@ def setup(log_file, logger, log_level=None):
log_file = default_file log_file = default_file
# print ('%r -- %r' % (log_level, log_file)) # print ('%r -- %r' % (log_level, log_file))
if logger != "access" and logger != "tornado.access":
r = logging.root
else:
r = logging.getLogger(logger) r = logging.getLogger(logger)
r.propagate = False
r.setLevel(log_level or DEFAULT_LOG_LEVEL) r.setLevel(log_level or DEFAULT_LOG_LEVEL)
previous_handler = r.handlers[0] if r.handlers else None previous_handler = r.handlers[0] if r.handlers else None

@ -42,7 +42,7 @@ from .web import login_required
oauth_check = {} oauth_check = {}
oauth = Blueprint('oauth', __name__) oauth = Blueprint('oauth', __name__)
# log = logger.create() log = logger.create()
def github_oauth_required(f): def github_oauth_required(f):
@ -105,7 +105,7 @@ def register_user_with_oauth(user=None):
try: try:
ub.session.commit() ub.session.commit()
except Exception as e: except Exception as e:
logger.exception(e) log.exception(e)
ub.session.rollback() ub.session.rollback()
@ -199,7 +199,7 @@ if ub.oauth_support:
ub.session.add(oauth) ub.session.add(oauth)
ub.session.commit() ub.session.commit()
except Exception as e: except Exception as e:
logger.exception(e) log.exception(e)
ub.session.rollback() ub.session.rollback()
# Disable Flask-Dance's default behavior for saving the OAuth token # Disable Flask-Dance's default behavior for saving the OAuth token
@ -225,7 +225,7 @@ if ub.oauth_support:
ub.session.add(oauth) ub.session.add(oauth)
ub.session.commit() ub.session.commit()
except Exception as e: except Exception as e:
logger.exception(e) log.exception(e)
ub.session.rollback() ub.session.rollback()
return redirect(url_for('web.login')) return redirect(url_for('web.login'))
#if config.config_public_reg: #if config.config_public_reg:
@ -268,11 +268,11 @@ if ub.oauth_support:
logout_oauth_user() logout_oauth_user()
flash(_(u"Unlink to %(oauth)s success.", oauth=oauth_check[provider]), category="success") flash(_(u"Unlink to %(oauth)s success.", oauth=oauth_check[provider]), category="success")
except Exception as e: except Exception as e:
logger.exception(e) log.exception(e)
ub.session.rollback() ub.session.rollback()
flash(_(u"Unlink to %(oauth)s failed.", oauth=oauth_check[provider]), category="error") flash(_(u"Unlink to %(oauth)s failed.", oauth=oauth_check[provider]), category="error")
except NoResultFound: except NoResultFound:
logger.warning("oauth %s for user %d not fount", provider, current_user.id) log.warning("oauth %s for user %d not fount", provider, current_user.id)
flash(_(u"Not linked to %(oauth)s.", oauth=oauth_check[provider]), category="error") flash(_(u"Not linked to %(oauth)s.", oauth=oauth_check[provider]), category="error")
return redirect(url_for('web.profile')) return redirect(url_for('web.profile'))

@ -34,11 +34,16 @@ except ImportError:
from tornado.httpserver import HTTPServer from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
from tornado import version as tornadoVersion from tornado import version as tornadoVersion
from tornado import log as tornadoLog
from tornado import options as tornadoOptions
gevent_present = False gevent_present = False
from . import logger, config, global_WorkerThread from . import logger, config, global_WorkerThread
log = logger.create()
class server: class server:
wsgiserver = None wsgiserver = None
@ -54,10 +59,13 @@ class server:
self.app = application self.app = application
self.port = config.config_port self.port = config.config_port
self.listening = config.get_config_ipaddress(readable=True) + ":" + str(self.port) self.listening = config.get_config_ipaddress(readable=True) + ":" + str(self.port)
self.access_logger = None
if config.config_access_log: if config.config_access_log:
if gevent_present:
logger.setup(config.config_access_logfile, logger.DEFAULT_ACCESS_LEVEL, "access")
self.access_logger = logging.getLogger("access") self.access_logger = logging.getLogger("access")
else: else:
self.access_logger = None logger.setup(config.config_access_logfile, logger.DEFAULT_ACCESS_LEVEL, "tornado.access")
self.ssl_args = None self.ssl_args = None
certfile_path = config.get_config_certfile() certfile_path = config.get_config_certfile()
@ -67,9 +75,9 @@ class server:
self.ssl_args = {"certfile": certfile_path, self.ssl_args = {"certfile": certfile_path,
"keyfile": keyfile_path} "keyfile": keyfile_path}
else: else:
logger.warning('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl.') log.warning('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl.')
logger.warning('Cert path: %s', certfile_path) log.warning('Cert path: %s', certfile_path)
logger.warning('Key path: %s', keyfile_path) log.warning('Key path: %s', keyfile_path)
def _make_gevent_socket(self): def _make_gevent_socket(self):
if config.get_config_ipaddress(): if config.get_config_ipaddress():
@ -80,15 +88,15 @@ class server:
try: try:
s = WSGIServer.get_listener(('', self.port), family=socket.AF_INET6) s = WSGIServer.get_listener(('', self.port), family=socket.AF_INET6)
except socket.error as ex: except socket.error as ex:
logger.error('%s', ex) log.error('%s', ex)
logger.warning('Unable to listen on \'\', trying on IPv4 only...') log.warning('Unable to listen on \'\', trying on IPv4 only...')
s = WSGIServer.get_listener(('', self.port), family=socket.AF_INET) s = WSGIServer.get_listener(('', self.port), family=socket.AF_INET)
logger.debug("%r %r", s._sock, s._sock.getsockname()) log.debug("%r %r", s._sock, s._sock.getsockname())
return s return s
def start_gevent(self): def start_gevent(self):
ssl_args = self.ssl_args or {} ssl_args = self.ssl_args or {}
logger.info('Starting Gevent server on %s', self.listening) log.info('Starting Gevent server')
try: try:
sock = self._make_gevent_socket() sock = self._make_gevent_socket()
@ -96,35 +104,34 @@ class server:
self.wsgiserver.serve_forever() self.wsgiserver.serve_forever()
except socket.error: except socket.error:
try: try:
logger.info('Unable to listen on "", trying on "0.0.0.0" only...') log.info('Unable to listen on "", trying on "0.0.0.0" only...')
self.wsgiserver = WSGIServer(('0.0.0.0', config.config_port), self.app, spawn=Pool(), **ssl_args) self.wsgiserver = WSGIServer(('0.0.0.0', config.config_port), self.app, spawn=Pool(), **ssl_args)
self.wsgiserver.serve_forever() self.wsgiserver.serve_forever()
except (OSError, socket.error) as e: except (OSError, socket.error) as e:
logger.info("Error starting server: %s", e.strerror) log.info("Error starting server: %s", e.strerror)
print("Error starting server: %s" % e.strerror) print("Error starting server: %s" % e.strerror)
global_WorkerThread.stop() global_WorkerThread.stop()
sys.exit(1) sys.exit(1)
except Exception: except Exception:
logger.exception("Unknown error while starting gevent") log.exception("Unknown error while starting gevent")
sys.exit(0) sys.exit(0)
def start_tornado(self): def start_tornado(self):
logger.info('Starting Tornado server on %s', self.listening) log.info('Starting Tornado server on %s', self.listening)
try: try:
# Max Buffersize set to 200MB # Max Buffersize set to 200MB )
http_server = HTTPServer(WSGIContainer(self.app), http_server = HTTPServer(WSGIContainer(self.app),
max_buffer_size = 209700000, max_buffer_size = 209700000,
ssl_options=self.ssl_args) ssl_options=self.ssl_args)
address = config.get_config_ipaddress() address = config.get_config_ipaddress()
http_server.listen(self.port, address) http_server.listen(self.port, address)
# self.access_log = logging.getLogger("tornado.access")
self.wsgiserver=IOLoop.instance() self.wsgiserver=IOLoop.instance()
self.wsgiserver.start() self.wsgiserver.start()
# wait for stop signal # wait for stop signal
self.wsgiserver.close(True) self.wsgiserver.close(True)
except socket.error as err: except socket.error as err:
logger.exception("Error starting tornado server") log.exception("Error starting tornado server")
print("Error starting server: %s" % err.strerror) print("Error starting server: %s" % err.strerror)
global_WorkerThread.stop() global_WorkerThread.stop()
sys.exit(1) sys.exit(1)
@ -137,7 +144,7 @@ class server:
self.start_tornado() self.start_tornado()
if self.restart is True: if self.restart is True:
logger.info("Performing restart of Calibre-Web") log.info("Performing restart of Calibre-Web")
global_WorkerThread.stop() global_WorkerThread.stop()
if os.name == 'nt': if os.name == 'nt':
arguments = ["\"" + sys.executable + "\""] arguments = ["\"" + sys.executable + "\""]
@ -147,7 +154,7 @@ class server:
else: else:
os.execl(sys.executable, sys.executable, *sys.argv) os.execl(sys.executable, sys.executable, *sys.argv)
else: else:
logger.info("Performing shutdown of Calibre-Web") log.info("Performing shutdown of Calibre-Web")
global_WorkerThread.stop() global_WorkerThread.stop()
sys.exit(0) sys.exit(0)

@ -33,7 +33,7 @@ from .web import render_title_template
shelf = Blueprint('shelf', __name__) shelf = Blueprint('shelf', __name__)
# log = logger.create() log = logger.create()
@shelf.route("/shelf/add/<int:shelf_id>/<int:book_id>") @shelf.route("/shelf/add/<int:shelf_id>/<int:book_id>")
@ -41,14 +41,14 @@ shelf = Blueprint('shelf', __name__)
def add_to_shelf(shelf_id, book_id): def add_to_shelf(shelf_id, book_id):
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
if shelf is None: if shelf is None:
logger.error("Invalid shelf specified: %s", shelf_id) log.error("Invalid shelf specified: %s", shelf_id)
if not request.is_xhr: if not request.is_xhr:
flash(_(u"Invalid shelf specified"), category="error") flash(_(u"Invalid shelf specified"), category="error")
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
return "Invalid shelf specified", 400 return "Invalid shelf specified", 400
if not shelf.is_public and not shelf.user_id == int(current_user.id): if not shelf.is_public and not shelf.user_id == int(current_user.id):
logger.error("User %s not allowed to add a book to %s", current_user, shelf) log.error("User %s not allowed to add a book to %s", current_user, shelf)
if not request.is_xhr: if not request.is_xhr:
flash(_(u"Sorry you are not allowed to add a book to the the shelf: %(shelfname)s", shelfname=shelf.name), flash(_(u"Sorry you are not allowed to add a book to the the shelf: %(shelfname)s", shelfname=shelf.name),
category="error") category="error")
@ -56,7 +56,7 @@ def add_to_shelf(shelf_id, book_id):
return "Sorry you are not allowed to add a book to the the shelf: %s" % shelf.name, 403 return "Sorry you are not allowed to add a book to the the shelf: %s" % shelf.name, 403
if shelf.is_public and not current_user.role_edit_shelfs(): if shelf.is_public and not current_user.role_edit_shelfs():
logger.info("User %s not allowed to edit public shelves", current_user) log.info("User %s not allowed to edit public shelves", current_user)
if not request.is_xhr: if not request.is_xhr:
flash(_(u"You are not allowed to edit public shelves"), category="error") flash(_(u"You are not allowed to edit public shelves"), category="error")
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
@ -65,7 +65,7 @@ def add_to_shelf(shelf_id, book_id):
book_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id, book_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id,
ub.BookShelf.book_id == book_id).first() ub.BookShelf.book_id == book_id).first()
if book_in_shelf: if book_in_shelf:
logger.error("Book %s is already part of %s", book_id, shelf) log.error("Book %s is already part of %s", book_id, shelf)
if not request.is_xhr: if not request.is_xhr:
flash(_(u"Book is already part of the shelf: %(shelfname)s", shelfname=shelf.name), category="error") flash(_(u"Book is already part of the shelf: %(shelfname)s", shelfname=shelf.name), category="error")
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
@ -94,17 +94,17 @@ def add_to_shelf(shelf_id, book_id):
def search_to_shelf(shelf_id): def search_to_shelf(shelf_id):
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
if shelf is None: if shelf is None:
logger.error("Invalid shelf specified: %s", shelf_id) log.error("Invalid shelf specified: %s", shelf_id)
flash(_(u"Invalid shelf specified"), category="error") flash(_(u"Invalid shelf specified"), category="error")
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
if not shelf.is_public and not shelf.user_id == int(current_user.id): if not shelf.is_public and not shelf.user_id == int(current_user.id):
logger.error("User %s not allowed to add a book to %s", current_user, shelf) log.error("User %s not allowed to add a book to %s", current_user, shelf)
flash(_(u"You are not allowed to add a book to the the shelf: %(name)s", name=shelf.name), category="error") flash(_(u"You are not allowed to add a book to the the shelf: %(name)s", name=shelf.name), category="error")
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
if shelf.is_public and not current_user.role_edit_shelfs(): if shelf.is_public and not current_user.role_edit_shelfs():
logger.error("User %s not allowed to edit public shelves", current_user) log.error("User %s not allowed to edit public shelves", current_user)
flash(_(u"User is not allowed to edit public shelves"), category="error") flash(_(u"User is not allowed to edit public shelves"), category="error")
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
@ -122,7 +122,7 @@ def search_to_shelf(shelf_id):
books_for_shelf = searched_ids[current_user.id] books_for_shelf = searched_ids[current_user.id]
if not books_for_shelf: if not books_for_shelf:
logger.error("Books are already part of %s", shelf) log.error("Books are already part of %s", shelf)
flash(_(u"Books are already part of the shelf: %(name)s", name=shelf.name), category="error") flash(_(u"Books are already part of the shelf: %(name)s", name=shelf.name), category="error")
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
@ -148,7 +148,7 @@ def search_to_shelf(shelf_id):
def remove_from_shelf(shelf_id, book_id): def remove_from_shelf(shelf_id, book_id):
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first() shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
if shelf is None: if shelf is None:
logger.error("Invalid shelf specified: %s", shelf_id) log.error("Invalid shelf specified: %s", shelf_id)
if not request.is_xhr: if not request.is_xhr:
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
return "Invalid shelf specified", 400 return "Invalid shelf specified", 400
@ -167,7 +167,7 @@ def remove_from_shelf(shelf_id, book_id):
ub.BookShelf.book_id == book_id).first() ub.BookShelf.book_id == book_id).first()
if book_shelf is None: if book_shelf is None:
logger.error("Book %s already removed from %s", book_id, shelf) log.error("Book %s already removed from %s", book_id, shelf)
if not request.is_xhr: if not request.is_xhr:
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
return "Book already removed from shelf", 410 return "Book already removed from shelf", 410
@ -180,7 +180,7 @@ def remove_from_shelf(shelf_id, book_id):
return redirect(request.environ["HTTP_REFERER"]) return redirect(request.environ["HTTP_REFERER"])
return "", 204 return "", 204
else: else:
logger.error("User %s not allowed to remove a book from %s", current_user, shelf) log.error("User %s not allowed to remove a book from %s", current_user, shelf)
if not request.is_xhr: if not request.is_xhr:
flash(_(u"Sorry you are not allowed to remove a book from this shelf: %(sname)s", sname=shelf.name), flash(_(u"Sorry you are not allowed to remove a book from this shelf: %(sname)s", sname=shelf.name),
category="error") category="error")
@ -262,7 +262,7 @@ def delete_shelf(shelf_id):
if deleted: if deleted:
ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).delete() ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id).delete()
ub.session.commit() ub.session.commit()
logger.info("successfully deleted %s", cur_shelf) log.info("successfully deleted %s", cur_shelf)
return redirect(url_for('web.index')) return redirect(url_for('web.index'))
# @shelf.route("/shelfdown/<int:shelf_id>") # @shelf.route("/shelfdown/<int:shelf_id>")
@ -289,7 +289,7 @@ def show_shelf(shelf_type, shelf_id):
if cur_book: if cur_book:
result.append(cur_book) result.append(cur_book)
else: else:
logger.info('Not existing book %s in %s deleted', book.book_id, shelf) log.info('Not existing book %s in %s deleted', book.book_id, shelf)
ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete() ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete()
ub.session.commit() ub.session.commit()
return render_title_template(page, entries=result, title=_(u"Shelf: '%(name)s'", name=shelf.name), return render_title_template(page, entries=result, title=_(u"Shelf: '%(name)s'", name=shelf.name),

@ -39,7 +39,6 @@ from sqlalchemy import String, Integer, SmallInteger, Boolean, DateTime
from sqlalchemy.orm import relationship, sessionmaker from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
import logging
try: try:
import ldap import ldap
@ -446,9 +445,7 @@ class Config:
self.config_rarfile_location = data.config_rarfile_location self.config_rarfile_location = data.config_rarfile_location
self.config_theme = data.config_theme self.config_theme = data.config_theme
self.config_updatechannel = data.config_updatechannel self.config_updatechannel = data.config_updatechannel
logger.setup(self.config_logfile, "general", self.config_log_level) logger.setup(self.config_logfile, self.config_log_level)
if self.config_access_log:
logger.setup("access.log", "access", logger.DEFAULT_ACCESS_LEVEL)
@property @property
def get_update_channel(self): def get_update_channel(self):

@ -36,7 +36,7 @@ from flask_babel import gettext as _
from . import constants, logger, config, get_locale, Server from . import constants, logger, config, get_locale, Server
# log = logger.create() log = logger.create()
_REPOSITORY_API_URL = 'https://api.github.com/repos/janeczku/calibre-web' _REPOSITORY_API_URL = 'https://api.github.com/repos/janeczku/calibre-web'
@ -72,45 +72,45 @@ class Updater(threading.Thread):
def run(self): def run(self):
try: try:
self.status = 1 self.status = 1
logger.debug(u'Download update file') log.debug(u'Download update file')
headers = {'Accept': 'application/vnd.github.v3+json'} headers = {'Accept': 'application/vnd.github.v3+json'}
r = requests.get(self._get_request_path(), stream=True, headers=headers) r = requests.get(self._get_request_path(), stream=True, headers=headers)
r.raise_for_status() r.raise_for_status()
self.status = 2 self.status = 2
logger.debug(u'Opening zipfile') log.debug(u'Opening zipfile')
z = zipfile.ZipFile(BytesIO(r.content)) z = zipfile.ZipFile(BytesIO(r.content))
self.status = 3 self.status = 3
logger.debug(u'Extracting zipfile') log.debug(u'Extracting zipfile')
tmp_dir = gettempdir() tmp_dir = gettempdir()
z.extractall(tmp_dir) z.extractall(tmp_dir)
foldername = os.path.join(tmp_dir, z.namelist()[0])[:-1] foldername = os.path.join(tmp_dir, z.namelist()[0])[:-1]
if not os.path.isdir(foldername): if not os.path.isdir(foldername):
self.status = 11 self.status = 11
logger.error(u'Extracted contents of zipfile not found in temp folder') log.info(u'Extracted contents of zipfile not found in temp folder')
return return
self.status = 4 self.status = 4
logger.debug(u'Replacing files') log.debug(u'Replacing files')
self.update_source(foldername, constants.BASE_DIR) self.update_source(foldername, constants.BASE_DIR)
self.status = 6 self.status = 6
logger.debug(u'Preparing restart of server') log.debug(u'Preparing restart of server')
time.sleep(2) time.sleep(2)
Server.setRestartTyp(True) Server.setRestartTyp(True)
Server.stopServer() Server.stopServer()
self.status = 7 self.status = 7
time.sleep(2) time.sleep(2)
except requests.exceptions.HTTPError as ex: except requests.exceptions.HTTPError as ex:
logger.info(u'HTTP Error %s', ex) log.info(u'HTTP Error %s', ex)
self.status = 8 self.status = 8
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
logger.info(u'Connection error') log.info(u'Connection error')
self.status = 9 self.status = 9
except requests.exceptions.Timeout: except requests.exceptions.Timeout:
logger.info(u'Timeout while establishing connection') log.info(u'Timeout while establishing connection')
self.status = 10 self.status = 10
except requests.exceptions.RequestException: except requests.exceptions.RequestException:
self.status = 11 self.status = 11
logger.info(u'General error') log.info(u'General error')
def get_update_status(self): def get_update_status(self):
return self.status return self.status
@ -159,12 +159,12 @@ class Updater(threading.Thread):
if sys.platform == "win32" or sys.platform == "darwin": if sys.platform == "win32" or sys.platform == "darwin":
change_permissions = False change_permissions = False
else: else:
logger.debug('Update on OS-System : %s', sys.platform) log.debug('Update on OS-System : %s', sys.platform)
for src_dir, __, files in os.walk(root_src_dir): for src_dir, __, files in os.walk(root_src_dir):
dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1) dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
if not os.path.exists(dst_dir): if not os.path.exists(dst_dir):
os.makedirs(dst_dir) os.makedirs(dst_dir)
logger.debug('Create-Dir: %s', dst_dir) log.debug('Create-Dir: %s', dst_dir)
if change_permissions: if change_permissions:
# print('Permissions: User '+str(new_permissions.st_uid)+' Group '+str(new_permissions.st_uid)) # print('Permissions: User '+str(new_permissions.st_uid)+' Group '+str(new_permissions.st_uid))
os.chown(dst_dir, new_permissions.st_uid, new_permissions.st_gid) os.chown(dst_dir, new_permissions.st_uid, new_permissions.st_gid)
@ -173,19 +173,19 @@ class Updater(threading.Thread):
dst_file = os.path.join(dst_dir, file_) dst_file = os.path.join(dst_dir, file_)
permission = os.stat(dst_file) permission = os.stat(dst_file)
if os.path.exists(dst_file): if os.path.exists(dst_file):
logger.debug('Remove file before copy: %s', dst_file) log.debug('Remove file before copy: %s', dst_file)
os.remove(dst_file) os.remove(dst_file)
else: else:
if change_permissions: if change_permissions:
permission = new_permissions permission = new_permissions
shutil.move(src_file, dst_dir) shutil.move(src_file, dst_dir)
logger.debug('Move File %s to %s', src_file, dst_dir) log.debug('Move File %s to %s', src_file, dst_dir)
if change_permissions: if change_permissions:
try: try:
os.chown(dst_file, permission.st_uid, permission.st_gid) os.chown(dst_file, permission.st_uid, permission.st_gid)
except OSError as e: except OSError as e:
old_permissions = os.stat(dst_file) old_permissions = os.stat(dst_file)
logger.debug('Fail change permissions of %s. Before: %s:%s After %s:%s error: %s', log.debug('Fail change permissions of %s. Before: %s:%s After %s:%s error: %s',
dst_file, old_permissions.st_uid, old_permissions.st_gid, dst_file, old_permissions.st_uid, old_permissions.st_gid,
permission.st_uid, permission.st_gid, e) permission.st_uid, permission.st_gid, e)
return return
@ -221,11 +221,11 @@ class Updater(threading.Thread):
for item in remove_items: for item in remove_items:
item_path = os.path.join(destination, item[1:]) item_path = os.path.join(destination, item[1:])
if os.path.isdir(item_path): if os.path.isdir(item_path):
logger.debug("Delete dir %s", item_path) log.debug("Delete dir %s", item_path)
shutil.rmtree(item_path, ignore_errors=True) shutil.rmtree(item_path, ignore_errors=True)
else: else:
try: try:
logger.debug("Delete file %s", item_path) log.debug("Delete file %s", item_path)
# log_from_thread("Delete file " + item_path) # log_from_thread("Delete file " + item_path)
os.remove(item_path) os.remove(item_path)
except OSError: except OSError:

@ -28,7 +28,7 @@ from . import logger, comic
from .constants import BookMeta from .constants import BookMeta
# log = logger.create() log = logger.create()
try: try:
@ -42,7 +42,7 @@ try:
from wand.exceptions import PolicyError from wand.exceptions import PolicyError
use_generic_pdf_cover = False use_generic_pdf_cover = False
except (ImportError, RuntimeError) as e: except (ImportError, RuntimeError) as e:
logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e) log.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
use_generic_pdf_cover = True use_generic_pdf_cover = True
try: try:
@ -50,21 +50,21 @@ try:
from PyPDF2 import __version__ as PyPdfVersion from PyPDF2 import __version__ as PyPdfVersion
use_pdf_meta = True use_pdf_meta = True
except ImportError as e: except ImportError as e:
logger.warning('cannot import PyPDF2, extracting pdf metadata will not work: %s', e) log.warning('cannot import PyPDF2, extracting pdf metadata will not work: %s', e)
use_pdf_meta = False use_pdf_meta = False
try: try:
from . import epub from . import epub
use_epub_meta = True use_epub_meta = True
except ImportError as e: except ImportError as e:
logger.warning('cannot import epub, extracting epub metadata will not work: %s', e) log.warning('cannot import epub, extracting epub metadata will not work: %s', e)
use_epub_meta = False use_epub_meta = False
try: try:
from . import fb2 from . import fb2
use_fb2_meta = True use_fb2_meta = True
except ImportError as e: except ImportError as e:
logger.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e) log.warning('cannot import fb2, extracting fb2 metadata will not work: %s', e)
use_fb2_meta = False use_fb2_meta = False
try: try:
@ -72,7 +72,7 @@ try:
from PIL import __version__ as PILversion from PIL import __version__ as PILversion
use_PIL = True use_PIL = True
except ImportError as e: except ImportError as e:
logger.warning('cannot import Pillow, using png and webp images as cover will not work: %s', e) log.warning('cannot import Pillow, using png and webp images as cover will not work: %s', e)
use_generic_pdf_cover = True use_generic_pdf_cover = True
use_PIL = False use_PIL = False
@ -94,7 +94,7 @@ def process(tmp_file_path, original_file_name, original_file_extension):
meta = comic.get_comic_info(tmp_file_path, original_file_name, original_file_extension) meta = comic.get_comic_info(tmp_file_path, original_file_name, original_file_extension)
except Exception as ex: except Exception as ex:
logger.warning('cannot parse metadata, using default: %s', ex) log.warning('cannot parse metadata, using default: %s', ex)
if meta and meta.title.strip() and meta.author.strip(): if meta and meta.title.strip() and meta.author.strip():
return meta return meta
@ -198,10 +198,10 @@ def pdf_preview(tmp_file_path, tmp_dir):
img.save(filename=os.path.join(tmp_dir, cover_file_name)) img.save(filename=os.path.join(tmp_dir, cover_file_name))
return cover_file_name return cover_file_name
except PolicyError as ex: except PolicyError as ex:
logger.warning('Pdf extraction forbidden by Imagemagick policy: %s', ex) log.warning('Pdf extraction forbidden by Imagemagick policy: %s', ex)
return None return None
except Exception as ex: except Exception as ex:
logger.warning('Cannot extract cover image, using default: %s', ex) log.warning('Cannot extract cover image, using default: %s', ex)
return None return None

@ -105,7 +105,7 @@ for ex in default_exceptions:
web = Blueprint('web', __name__) web = Blueprint('web', __name__)
# log = logger.create() log = logger.create()
# ################################### Login logic and rights management ############################################### # ################################### Login logic and rights management ###############################################
@ -308,7 +308,7 @@ def toggle_read(book_id):
db.session.add(new_cc) db.session.add(new_cc)
db.session.commit() db.session.commit()
except KeyError: except KeyError:
logger.error(u"Custom Column No.%d is not exisiting in calibre database", config.config_read_column) log.error(u"Custom Column No.%d is not exisiting in calibre database", config.config_read_column)
return "" return ""
''' '''
@ -331,10 +331,10 @@ def get_comic_book(book_id, book_format, page):
extract = lambda page: rf.read(names[page]) extract = lambda page: rf.read(names[page])
except: except:
# rarfile not valid # rarfile not valid
logger.error('Unrar binary not found, or unable to decompress file %s', cbr_file) log.error('Unrar binary not found, or unable to decompress file %s', cbr_file)
return "", 204 return "", 204
else: else:
logger.info('Unrar is not supported please install python rarfile extension') log.info('Unrar is not supported please install python rarfile extension')
# no support means return nothing # no support means return nothing
return "", 204 return "", 204
elif book_format in ("cbz", "zip"): elif book_format in ("cbz", "zip"):
@ -346,7 +346,7 @@ def get_comic_book(book_id, book_format, page):
names=sort(tf.getnames()) names=sort(tf.getnames())
extract = lambda page: tf.extractfile(names[page]).read() extract = lambda page: tf.extractfile(names[page]).read()
else: else:
logger.error('unsupported comic format') log.error('unsupported comic format')
return "", 204 return "", 204
if sys.version_info.major >= 3: if sys.version_info.major >= 3:
@ -937,7 +937,7 @@ def render_read_books(page, are_read, as_xml=False, order=None):
.filter(db.cc_classes[config.config_read_column].value is True).all() .filter(db.cc_classes[config.config_read_column].value is True).all()
readBookIds = [x.book for x in readBooks] readBookIds = [x.book for x in readBooks]
except KeyError: except KeyError:
logger.error("Custom Column No.%d is not existing in calibre database", config.config_read_column) log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column)
readBookIds = [] readBookIds = []
if are_read: if are_read:
@ -980,7 +980,7 @@ def serve_book(book_id, book_format):
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper())\ data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper())\
.first() .first()
logger.info('Serving book: %s', data.name) log.info('Serving book: %s', data.name)
if config.config_use_google_drive: if config.config_use_google_drive:
headers = Headers() headers = Headers()
try: try:
@ -1063,7 +1063,7 @@ def register():
return render_title_template('register.html', title=_(u"register"), page="register") return render_title_template('register.html', title=_(u"register"), page="register")
else: else:
flash(_(u"Your e-mail is not allowed to register"), category="error") flash(_(u"Your e-mail is not allowed to register"), category="error")
logger.info('Registering failed for user "%s" e-mail adress: %s', to_save['nickname'], to_save["email"]) log.info('Registering failed for user "%s" e-mail adress: %s', to_save['nickname'], to_save["email"])
return render_title_template('register.html', title=_(u"register"), page="register") return render_title_template('register.html', title=_(u"register"), page="register")
flash(_(u"Confirmation e-mail was send to your e-mail account."), category="success") flash(_(u"Confirmation e-mail was send to your e-mail account."), category="success")
return redirect(url_for('web.login')) return redirect(url_for('web.login'))
@ -1095,10 +1095,10 @@ def login():
return redirect_back(url_for("web.index")) return redirect_back(url_for("web.index"))
except ldap.INVALID_CREDENTIALS: except ldap.INVALID_CREDENTIALS:
ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr) ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr)
logger.info('LDAP Login failed for user "%s" IP-adress: %s', form['username'], ipAdress) log.info('LDAP Login failed for user "%s" IP-adress: %s', form['username'], ipAdress)
flash(_(u"Wrong Username or Password"), category="error") flash(_(u"Wrong Username or Password"), category="error")
except ldap.SERVER_DOWN: except ldap.SERVER_DOWN:
logger.info('LDAP Login failed, LDAP Server down') log.info('LDAP Login failed, LDAP Server down')
flash(_(u"Could not login. LDAP server down, please contact your administrator"), category="error") flash(_(u"Could not login. LDAP server down, please contact your administrator"), category="error")
else: else:
if user and check_password_hash(user.password, form['password']) and user.nickname is not "Guest": if user and check_password_hash(user.password, form['password']) and user.nickname is not "Guest":
@ -1107,7 +1107,7 @@ def login():
return redirect_back(url_for("web.index")) return redirect_back(url_for("web.index"))
else: else:
ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr) ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr)
logger.info('Login failed for user "%s" IP-adress: %s', form['username'], ipAdress) log.info('Login failed for user "%s" IP-adress: %s', form['username'], ipAdress)
flash(_(u"Wrong Username or Password"), category="error") flash(_(u"Wrong Username or Password"), category="error")
next_url = url_for('web.index') next_url = url_for('web.index')
@ -1348,7 +1348,7 @@ def show_book(book_id):
matching_have_read_book = getattr(entries, 'custom_column_'+str(config.config_read_column)) matching_have_read_book = getattr(entries, 'custom_column_'+str(config.config_read_column))
have_read = len(matching_have_read_book) > 0 and matching_have_read_book[0].value have_read = len(matching_have_read_book) > 0 and matching_have_read_book[0].value
except KeyError: except KeyError:
logger.error("Custom Column No.%d is not exisiting in calibre database", config.config_read_column) log.error("Custom Column No.%d is not exisiting in calibre database", config.config_read_column)
have_read = None have_read = None
else: else:

@ -48,7 +48,7 @@ from . import logger, config, db, gdriveutils
from .subproc_wrapper import process_open from .subproc_wrapper import process_open
# log = logger.create() log = logger.create()
chunksize = 8192 chunksize = 8192
# task 'status' consts # task 'status' consts
@ -90,8 +90,8 @@ def get_attachment(bookpath, filename):
data = file_.read() data = file_.read()
file_.close() file_.close()
except IOError as e: except IOError as e:
logger.exception(e) # traceback.print_exc() log.exception(e) # traceback.print_exc()
logger.error(u'The requested file could not be read. Maybe wrong permissions?') log.error(u'The requested file could not be read. Maybe wrong permissions?')
return None return None
attachment = MIMEBase('application', 'octet-stream') attachment = MIMEBase('application', 'octet-stream')
@ -116,7 +116,7 @@ class emailbase():
def send(self, strg): def send(self, strg):
"""Send `strg' to the server.""" """Send `strg' to the server."""
logger.debug('send: %r', strg[:300]) log.debug('send: %r', strg[:300])
if hasattr(self, 'sock') and self.sock: if hasattr(self, 'sock') and self.sock:
try: try:
if self.transferSize: if self.transferSize:
@ -142,7 +142,7 @@ class emailbase():
@classmethod @classmethod
def _print_debug(self, *args): def _print_debug(self, *args):
logger.debug(args) log.debug(args)
def getTransferStatus(self): def getTransferStatus(self):
if self.transferSize: if self.transferSize:
@ -257,14 +257,14 @@ class WorkerThread(threading.Thread):
# if it does - mark the conversion task as complete and return a success # if it does - mark the conversion task as complete and return a success
# this will allow send to kindle workflow to continue to work # this will allow send to kindle workflow to continue to work
if os.path.isfile(file_path + format_new_ext): if os.path.isfile(file_path + format_new_ext):
logger.info("Book id %d already converted to %s", bookid, format_new_ext) log.info("Book id %d already converted to %s", bookid, format_new_ext)
cur_book = db.session.query(db.Books).filter(db.Books.id == bookid).first() cur_book = db.session.query(db.Books).filter(db.Books.id == bookid).first()
self.queue[self.current]['path'] = file_path self.queue[self.current]['path'] = file_path
self.queue[self.current]['title'] = cur_book.title self.queue[self.current]['title'] = cur_book.title
self._handleSuccess() self._handleSuccess()
return file_path + format_new_ext return file_path + format_new_ext
else: else:
logger.info("Book id %d - target format of %s does not exist. Moving forward with convert.", bookid, format_new_ext) log.info("Book id %d - target format of %s does not exist. Moving forward with convert.", bookid, format_new_ext)
# check if converter-executable is existing # check if converter-executable is existing
if not os.path.exists(config.config_converterpath): if not os.path.exists(config.config_converterpath):
@ -320,13 +320,13 @@ class WorkerThread(threading.Thread):
if conv_error: if conv_error:
error_message = _(u"Kindlegen failed with Error %(error)s. Message: %(message)s", error_message = _(u"Kindlegen failed with Error %(error)s. Message: %(message)s",
error=conv_error.group(1), message=conv_error.group(2).strip()) error=conv_error.group(1), message=conv_error.group(2).strip())
logger.debug("convert_kindlegen: %s", nextline) log.debug("convert_kindlegen: %s", nextline)
else: else:
while p.poll() is None: while p.poll() is None:
nextline = p.stdout.readline() nextline = p.stdout.readline()
if os.name == 'nt' and sys.version_info < (3, 0): if os.name == 'nt' and sys.version_info < (3, 0):
nextline = nextline.decode('windows-1252') nextline = nextline.decode('windows-1252')
logger.debug(nextline.strip('\r\n')) log.debug(nextline.strip('\r\n'))
# parse progress string from calibre-converter # parse progress string from calibre-converter
progress = re.search("(\d+)%\s.*", nextline) progress = re.search("(\d+)%\s.*", nextline)
if progress: if progress:
@ -356,7 +356,7 @@ class WorkerThread(threading.Thread):
return file_path + format_new_ext return file_path + format_new_ext
else: else:
error_message = format_new_ext.upper() + ' format not found on disk' error_message = format_new_ext.upper() + ' format not found on disk'
logger.info("ebook converter failed with error while converting book") log.info("ebook converter failed with error while converting book")
if not error_message: if not error_message:
error_message = 'Ebook converter failed with unknown error' error_message = 'Ebook converter failed with unknown error'
self._handleError(error_message) self._handleError(error_message)
@ -460,7 +460,7 @@ class WorkerThread(threading.Thread):
self.asyncSMTP = email(obj['settings']["mail_server"], obj['settings']["mail_port"], timeout) self.asyncSMTP = email(obj['settings']["mail_server"], obj['settings']["mail_port"], timeout)
# link to logginglevel # link to logginglevel
if logger.is_debug_enabled('general'): if logger.is_debug_enabled():
self.asyncSMTP.set_debuglevel(1) self.asyncSMTP.set_debuglevel(1)
if use_ssl == 1: if use_ssl == 1:
self.asyncSMTP.starttls() self.asyncSMTP.starttls()
@ -502,7 +502,7 @@ class WorkerThread(threading.Thread):
return retVal return retVal
def _handleError(self, error_message): def _handleError(self, error_message):
logger.error(error_message) log.error(error_message)
self.UIqueue[self.current]['stat'] = STAT_FAIL self.UIqueue[self.current]['stat'] = STAT_FAIL
self.UIqueue[self.current]['progress'] = "100 %" self.UIqueue[self.current]['progress'] = "100 %"
self.UIqueue[self.current]['runtime'] = self._formatRuntime( self.UIqueue[self.current]['runtime'] = self._formatRuntime(

Loading…
Cancel
Save