diff --git a/config.py b/config.py
index aa9221023..00ec14f21 100644
--- a/config.py
+++ b/config.py
@@ -1,17 +1,18 @@
import os
import sys
-# TODO: move all logging back to pyfa.py main loop
-# We moved it here just to avoid rebuilding windows skeleton for now (any change to pyfa.py needs it)
-import logging
-import logging.handlers
+from logbook import Logger
+
+pyfalog = Logger(__name__)
# Load variable overrides specific to distribution type
try:
import configforced
except ImportError:
+ pyfalog.warning("Failed to import: configforced")
configforced = None
+
# Turns on debug mode
debug = False
# Defines if our saveddata will be in pyfa root or not
@@ -29,23 +30,6 @@ savePath = None
saveDB = None
gameDB = None
-
-class StreamToLogger(object):
- """
- Fake file-like stream object that redirects writes to a logger instance.
- From: http://www.electricmonk.nl/log/2011/08/14/redirect-stdout-and-stderr-to-a-logger-in-python/
- """
-
- def __init__(self, logger, log_level=logging.INFO):
- self.logger = logger
- self.log_level = log_level
- self.linebuf = ''
-
- def write(self, buf):
- for line in buf.rstrip().splitlines():
- self.logger.log(self.log_level, line.rstrip())
-
-
def isFrozen():
if hasattr(sys, 'frozen'):
return True
@@ -66,10 +50,7 @@ def defPaths(customSavePath):
global gameDB
global saveInRoot
- if debug:
- logLevel = logging.DEBUG
- else:
- logLevel = logging.WARN
+ pyfalog.debug("Configuring Pyfa")
# The main pyfa directory which contains run.py
# Python 2.X uses ANSI by default, so we need to convert the character encoding
@@ -97,25 +78,6 @@ def defPaths(customSavePath):
os.environ["REQUESTS_CA_BUNDLE"] = getPyfaPath(certName).encode('utf8')
os.environ["SSL_CERT_FILE"] = getPyfaPath(certName).encode('utf8')
- loggingFormat = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s'
- logging.basicConfig(format=loggingFormat, level=logLevel)
- handler = logging.handlers.RotatingFileHandler(getSavePath("log.txt"), maxBytes=1000000, backupCount=3)
- formatter = logging.Formatter(loggingFormat)
- handler.setFormatter(formatter)
- logging.getLogger('').addHandler(handler)
-
- logging.info("Starting pyfa")
-
- if hasattr(sys, 'frozen'):
- stdout_logger = logging.getLogger('STDOUT')
- sl = StreamToLogger(stdout_logger, logging.INFO)
- sys.stdout = sl
-
- # This interferes with cx_Freeze's own handling of exceptions. Find a way to fix this.
- # stderr_logger = logging.getLogger('STDERR')
- # sl = StreamToLogger(stderr_logger, logging.ERROR)
- # sys.stderr = sl
-
# The database where we store all the fits etc
saveDB = getSavePath("saveddata.db")
diff --git a/eos/db/__init__.py b/eos/db/__init__.py
index aa320892a..dda1b34ff 100644
--- a/eos/db/__init__.py
+++ b/eos/db/__init__.py
@@ -24,6 +24,9 @@ from sqlalchemy.orm import sessionmaker
import migration
from eos import config
+from logbook import Logger
+
+pyfalog = Logger(__name__)
class ReadOnlyException(Exception):
@@ -47,6 +50,7 @@ try:
"SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'client_build'"
).fetchone()[0]
except:
+ pyfalog.warning("Missing gamedata version.")
config.gamedata_version = None
saveddata_connectionstring = config.saveddata_connectionstring
diff --git a/eos/db/migration.py b/eos/db/migration.py
index 6dc59565c..c8fdcb4ac 100644
--- a/eos/db/migration.py
+++ b/eos/db/migration.py
@@ -1,11 +1,11 @@
-import logging
+from logbook import Logger
import shutil
import time
import config
import migrations
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
def getVersion(db):
@@ -37,7 +37,7 @@ def update(saveddata_engine):
for version in xrange(dbVersion, appVersion):
func = migrations.updates[version + 1]
if func:
- logger.info("Applying database update: %d", version + 1)
+ pyfalog.info("Applying database update: %d", version + 1)
func(saveddata_engine)
# when all is said and done, set version to current
diff --git a/eos/db/saveddata/databaseRepair.py b/eos/db/saveddata/databaseRepair.py
index 994583ce5..0d133d5e6 100644
--- a/eos/db/saveddata/databaseRepair.py
+++ b/eos/db/saveddata/databaseRepair.py
@@ -18,9 +18,9 @@
# ===============================================================================
from sqlalchemy.exc import DatabaseError
-import logging
+from logbook import Logger
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class DatabaseCleanup(object):
@@ -33,7 +33,7 @@ class DatabaseCleanup(object):
results = saveddata_engine.execute(query)
return results
except DatabaseError:
- logger.error("Failed to connect to database or error executing query:\n%s", query)
+ pyfalog.error("Failed to connect to database or error executing query:\n{0}", query)
return None
@staticmethod
@@ -41,7 +41,7 @@ class DatabaseCleanup(object):
# Find orphaned character skills.
# This solves an issue where the character doesn't exist, but skills for that character do.
# See issue #917
- logger.debug("Running database cleanup for character skills.")
+ pyfalog.debug("Running database cleanup for character skills.")
query = "SELECT COUNT(*) AS num FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)"
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
@@ -53,14 +53,14 @@ class DatabaseCleanup(object):
if row and row['num']:
query = "DELETE FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)"
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
- logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
+ pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
@staticmethod
def OrphanedFitDamagePatterns(saveddata_engine):
# Find orphaned damage patterns.
# This solves an issue where the damage pattern doesn't exist, but fits reference the pattern.
# See issue #777
- logger.debug("Running database cleanup for orphaned damage patterns attached to fits.")
+ pyfalog.debug("Running database cleanup for orphaned damage patterns attached to fits.")
query = "SELECT COUNT(*) AS num FROM fits WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL"
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
@@ -80,20 +80,20 @@ class DatabaseCleanup(object):
rows = uniform_results.fetchall()
if len(rows) == 0:
- logger.error("Missing uniform damage pattern.")
+ pyfalog.error("Missing uniform damage pattern.")
elif len(rows) > 1:
- logger.error("More than one uniform damage pattern found.")
+ pyfalog.error("More than one uniform damage pattern found.")
else:
uniform_damage_pattern_id = rows[0]['ID']
update_query = "UPDATE 'fits' SET 'damagePatternID' = {} " \
"WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL".format(uniform_damage_pattern_id)
update_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, update_query)
- logger.error("Database corruption found. Cleaning up %d records.", update_results.rowcount)
+ pyfalog.error("Database corruption found. Cleaning up {0} records.", update_results.rowcount)
@staticmethod
def OrphanedFitCharacterIDs(saveddata_engine):
# Find orphaned character IDs. This solves an issue where the character doesn't exist, but fits reference the pattern.
- logger.debug("Running database cleanup for orphaned characters attached to fits.")
+ pyfalog.debug("Running database cleanup for orphaned characters attached to fits.")
query = "SELECT COUNT(*) AS num FROM fits WHERE characterID NOT IN (SELECT ID FROM characters) OR characterID IS NULL"
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
@@ -113,22 +113,22 @@ class DatabaseCleanup(object):
rows = all5_results.fetchall()
if len(rows) == 0:
- logger.error("Missing 'All 5' character.")
+ pyfalog.error("Missing 'All 5' character.")
elif len(rows) > 1:
- logger.error("More than one 'All 5' character found.")
+ pyfalog.error("More than one 'All 5' character found.")
else:
all5_id = rows[0]['ID']
update_query = "UPDATE 'fits' SET 'characterID' = " + str(all5_id) + \
" WHERE characterID not in (select ID from characters) OR characterID IS NULL"
update_results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, update_query)
- logger.error("Database corruption found. Cleaning up %d records.", update_results.rowcount)
+ pyfalog.error("Database corruption found. Cleaning up {0} records.", update_results.rowcount)
@staticmethod
def NullDamagePatternNames(saveddata_engine):
# Find damage patterns that are missing the name.
# This solves an issue where the damage pattern ends up with a name that is null.
# See issue #949
- logger.debug("Running database cleanup for missing damage pattern names.")
+ pyfalog.debug("Running database cleanup for missing damage pattern names.")
query = "SELECT COUNT(*) AS num FROM damagePatterns WHERE name IS NULL OR name = ''"
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
@@ -140,14 +140,14 @@ class DatabaseCleanup(object):
if row and row['num']:
query = "DELETE FROM damagePatterns WHERE name IS NULL OR name = ''"
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
- logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
+ pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
@staticmethod
def NullTargetResistNames(saveddata_engine):
# Find target resists that are missing the name.
# This solves an issue where the target resist ends up with a name that is null.
# See issue #949
- logger.debug("Running database cleanup for missing target resist names.")
+ pyfalog.debug("Running database cleanup for missing target resist names.")
query = "SELECT COUNT(*) AS num FROM targetResists WHERE name IS NULL OR name = ''"
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
@@ -159,14 +159,14 @@ class DatabaseCleanup(object):
if row and row['num']:
query = "DELETE FROM targetResists WHERE name IS NULL OR name = ''"
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
- logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
+ pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
@staticmethod
def OrphanedFitIDItemID(saveddata_engine):
# Orphaned items that are missing the fit ID or item ID.
# See issue #954
for table in ['drones', 'cargo', 'fighters']:
- logger.debug("Running database cleanup for orphaned %s items.", table)
+ pyfalog.debug("Running database cleanup for orphaned {0} items.", table)
query = "SELECT COUNT(*) AS num FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(
table)
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
@@ -180,10 +180,10 @@ class DatabaseCleanup(object):
query = "DELETE FROM {} WHERE itemID IS NULL OR itemID = '' or itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(
table)
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
- logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
+ pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
for table in ['modules']:
- logger.debug("Running database cleanup for orphaned %s items.", table)
+ pyfalog.debug("Running database cleanup for orphaned {0} items.", table)
query = "SELECT COUNT(*) AS num FROM {} WHERE itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(
table)
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
@@ -196,7 +196,7 @@ class DatabaseCleanup(object):
if row and row['num']:
query = "DELETE FROM {} WHERE itemID = '0' or fitID IS NULL OR fitID = '' or fitID = '0'".format(table)
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
- logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
+ pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
@staticmethod
def NullDamageTargetPatternValues(saveddata_engine):
@@ -204,7 +204,7 @@ class DatabaseCleanup(object):
# See issue #954
for profileType in ['damagePatterns', 'targetResists']:
for damageType in ['em', 'thermal', 'kinetic', 'explosive']:
- logger.debug("Running database cleanup for null %s values. (%s)", profileType, damageType)
+ pyfalog.debug("Running database cleanup for null {0} values. ({1})", profileType, damageType)
query = "SELECT COUNT(*) AS num FROM {0} WHERE {1}Amount IS NULL OR {1}Amount = ''".format(profileType,
damageType)
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
@@ -218,13 +218,13 @@ class DatabaseCleanup(object):
query = "UPDATE '{0}' SET '{1}Amount' = '0' WHERE {1}Amount IS NULL OR Amount = ''".format(profileType,
damageType)
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
- logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
+ pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
@staticmethod
def DuplicateSelectedAmmoName(saveddata_engine):
# Orphaned items that are missing the fit ID or item ID.
# See issue #954
- logger.debug("Running database cleanup for duplicated selected ammo profiles.")
+ pyfalog.debug("Running database cleanup for duplicated selected ammo profiles.")
query = "SELECT COUNT(*) AS num FROM damagePatterns WHERE name = 'Selected Ammo'"
results = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
@@ -236,4 +236,4 @@ class DatabaseCleanup(object):
if row and row['num'] > 1:
query = "DELETE FROM damagePatterns WHERE name = 'Selected Ammo'"
delete = DatabaseCleanup.ExecuteSQLQuery(saveddata_engine, query)
- logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
+ pyfalog.error("Database corruption found. Cleaning up {0} records.", delete.rowcount)
diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py
index 0814d901f..e14162523 100644
--- a/eos/effectHandlerHelpers.py
+++ b/eos/effectHandlerHelpers.py
@@ -17,9 +17,9 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class HandledList(list):
@@ -198,7 +198,7 @@ class HandledImplantBoosterList(HandledList):
# if needed, remove booster that was occupying slot
oldObj = next((m for m in self if m.slot == thing.slot), None)
if oldObj:
- logging.info("Slot %d occupied with %s, replacing with %s", thing.slot, oldObj.item.name, thing.item.name)
+ pyfalog.info("Slot %d occupied with %s, replacing with %s", thing.slot, oldObj.item.name, thing.item.name)
oldObj.itemID = 0 # hack to remove from DB. See GH issue #324
self.remove(oldObj)
@@ -222,7 +222,7 @@ class HandledProjectedModList(HandledList):
oldEffect = next((m for m in self if m.item.group.name == "Effect Beacon"), None)
if oldEffect:
- logging.info("System effect occupied with %s, replacing with %s", oldEffect.item.name, proj.item.name)
+ pyfalog.info("System effect occupied with %s, replacing with %s", oldEffect.item.name, proj.item.name)
self.remove(oldEffect)
HandledList.append(self, proj)
diff --git a/eos/effects/adaptivearmorhardener.py b/eos/effects/adaptivearmorhardener.py
index e25fe48d4..8d017715d 100644
--- a/eos/effects/adaptivearmorhardener.py
+++ b/eos/effects/adaptivearmorhardener.py
@@ -2,9 +2,9 @@
#
# Used by:
# Module: Reactive Armor Hardener
-import logging
+from logbook import Logger
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
runTime = "late"
type = "active"
@@ -23,7 +23,7 @@ def handler(fit, module, context):
damagePattern.kineticAmount * fit.ship.getModifiedItemAttr('armorKineticDamageResonance'),
damagePattern.explosiveAmount * fit.ship.getModifiedItemAttr('armorExplosiveDamageResonance'),
)
- # logger.debug("Damage Adjusted for Armor Resists: %f/%f/%f/%f", baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3])
+ # pyfalog.debug("Damage Adjusted for Armor Resists: %f/%f/%f/%f", baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3])
resistanceShiftAmount = module.getModifiedItemAttr(
'resistanceShiftAmount') / 100 # The attribute is in percent and we want a fraction
@@ -39,7 +39,7 @@ def handler(fit, module, context):
cycleList = []
loopStart = -20
for num in range(50):
- # logger.debug("Starting cycle %d.", num)
+ # pyfalog.debug("Starting cycle %d.", num)
# The strange order is to emulate the ingame sorting when different types have taken the same amount of damage.
# This doesn't take into account stacking penalties. In a few cases fitting a Damage Control causes an inaccurate result.
damagePattern_tuples = [
@@ -77,7 +77,7 @@ def handler(fit, module, context):
RAHResistance[sortedDamagePattern_tuples[1][0]] = sortedDamagePattern_tuples[1][2] + change1
RAHResistance[sortedDamagePattern_tuples[2][0]] = sortedDamagePattern_tuples[2][2] + change2
RAHResistance[sortedDamagePattern_tuples[3][0]] = sortedDamagePattern_tuples[3][2] + change3
- # logger.debug("Resistances shifted to %f/%f/%f/%f", RAHResistance[0], RAHResistance[1], RAHResistance[2], RAHResistance[3])
+ # pyfalog.debug("Resistances shifted to %f/%f/%f/%f", RAHResistance[0], RAHResistance[1], RAHResistance[2], RAHResistance[3])
# See if the current RAH profile has been encountered before, indicating a loop.
for i, val in enumerate(cycleList):
@@ -87,7 +87,7 @@ def handler(fit, module, context):
abs(RAHResistance[2] - val[2]) <= tolerance and \
abs(RAHResistance[3] - val[3]) <= tolerance:
loopStart = i
- # logger.debug("Loop found: %d-%d", loopStart, num)
+ # pyfalog.debug("Loop found: %d-%d", loopStart, num)
break
if loopStart >= 0:
break
@@ -95,7 +95,7 @@ def handler(fit, module, context):
cycleList.append(list(RAHResistance))
if loopStart < 0:
- logger.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: %f/%f/%f/%f",
+ pyfalog.error("Reactive Armor Hardener failed to find equilibrium. Damage profile after armor: {0}/{1}/{2}/{3}",
baseDamageTaken[0], baseDamageTaken[1], baseDamageTaken[2], baseDamageTaken[3])
# Average the profiles in the RAH loop, or the last 20 if it didn't find a loop.
@@ -110,7 +110,7 @@ def handler(fit, module, context):
average[i] = round(average[i] / numCycles, 3)
# Set the new resistances
- # logger.debug("Setting new resist profile: %f/%f/%f/%f", average[0], average[1], average[2],average[3])
+ # pyfalog.debug("Setting new resist profile: %f/%f/%f/%f", average[0], average[1], average[2],average[3])
for i, attr in enumerate((
'armorEmDamageResonance', 'armorThermalDamageResonance', 'armorKineticDamageResonance',
'armorExplosiveDamageResonance')):
diff --git a/eos/gamedata.py b/eos/gamedata.py
index d46f1032b..97df52292 100644
--- a/eos/gamedata.py
+++ b/eos/gamedata.py
@@ -30,6 +30,9 @@ try:
except ImportError:
from utils.compat import OrderedDict
+from logbook import Logger
+pyfalog = Logger(__name__)
+
class Effect(EqBase):
"""
@@ -67,6 +70,8 @@ class Effect(EqBase):
if not self.__generated:
self.__generateHandler()
+ pyfalog.debug("Generating effect: {0} ({1}) [runTime: {2}]", self.name, self.effectID, self.runTime)
+
return self.__handler
@property
@@ -141,7 +146,7 @@ class Effect(EqBase):
@property
def isImplemented(self):
"""
- Wether this effect is implemented in code or not,
+ Whether this effect is implemented in code or not,
unimplemented effects simply do nothing at all when run
"""
return self.handler != effectDummy
@@ -182,13 +187,16 @@ class Effect(EqBase):
t = t if isinstance(t, tuple) or t is None else (t,)
self.__type = t
- except (ImportError, AttributeError):
+ except (ImportError, AttributeError) as e:
self.__handler = effectDummy
self.__runTime = "normal"
self.__activeByDefault = True
self.__type = None
+ pyfalog.debug("ImportError or AttributeError generating handler:")
+ pyfalog.warning(e)
except Exception as e:
- traceback.print_exc(e)
+ pyfalog.critical("Exception generating handler:")
+ pyfalog.critical(e)
self.__generated = True
diff --git a/eos/graph/fitDps.py b/eos/graph/fitDps.py
index 221cbb3a1..3c039e903 100644
--- a/eos/graph/fitDps.py
+++ b/eos/graph/fitDps.py
@@ -21,6 +21,9 @@ from math import log, sin, radians, exp
from eos.graph import Graph
from eos.saveddata.module import State, Hardpoint
+from logbook import Logger
+
+pyfalog = Logger(__name__)
class FitDpsGraph(Graph):
@@ -66,6 +69,7 @@ class FitDpsGraph(Graph):
val *= 1 + (bonus - 1) * exp(- i ** 2 / 7.1289)
data[attr] = val
except:
+ pyfalog.warning("Caught exception in calcDPS.")
pass
for mod in fit.modules:
diff --git a/eos/saveddata/booster.py b/eos/saveddata/booster.py
index 0798175d7..a424ff75f 100644
--- a/eos/saveddata/booster.py
+++ b/eos/saveddata/booster.py
@@ -17,7 +17,7 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
from sqlalchemy.orm import reconstructor, validates
@@ -25,7 +25,7 @@ import eos.db
from eos.effectHandlerHelpers import HandledItem
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Booster(HandledItem, ItemAttrShortcut):
@@ -47,11 +47,11 @@ class Booster(HandledItem, ItemAttrShortcut):
if self.itemID:
self.__item = eos.db.getItem(self.itemID)
if self.__item is None:
- logger.error("Item (id: %d) does not exist", self.itemID)
+ pyfalog.error("Item (id: %d) does not exist", self.itemID)
return
if self.isInvalid:
- logger.error("Item (id: %d) is not a Booser", self.itemID)
+ pyfalog.error("Item (id: %d) is not a Booser", self.itemID)
return
self.build()
diff --git a/eos/saveddata/cargo.py b/eos/saveddata/cargo.py
index 70bb150c9..1f76063b0 100644
--- a/eos/saveddata/cargo.py
+++ b/eos/saveddata/cargo.py
@@ -18,7 +18,7 @@
# ===============================================================================
import sys
-import logging
+from logbook import Logger
from sqlalchemy.orm import validates, reconstructor
@@ -26,7 +26,7 @@ import eos.db
from eos.effectHandlerHelpers import HandledItem
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Cargo(HandledItem, ItemAttrShortcut):
@@ -47,7 +47,7 @@ class Cargo(HandledItem, ItemAttrShortcut):
if self.itemID:
self.__item = eos.db.getItem(self.itemID)
if self.__item is None:
- logger.error("Item (id: %d) does not exist", self.itemID)
+ pyfalog.error("Item (id: %d) does not exist", self.itemID)
return
self.__itemModifiedAttributes = ModifiedAttributeDict()
diff --git a/eos/saveddata/character.py b/eos/saveddata/character.py
index 4332944c2..eea3e6b8f 100644
--- a/eos/saveddata/character.py
+++ b/eos/saveddata/character.py
@@ -18,7 +18,7 @@
# ===============================================================================
-import logging
+from logbook import Logger
from itertools import chain
from sqlalchemy.orm import validates, reconstructor
@@ -27,7 +27,7 @@ import eos
import eos.db
from eos.effectHandlerHelpers import HandledItem, HandledImplantBoosterList
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Character(object):
diff --git a/eos/saveddata/citadel.py b/eos/saveddata/citadel.py
index 6e1654028..ccb68fc78 100644
--- a/eos/saveddata/citadel.py
+++ b/eos/saveddata/citadel.py
@@ -17,16 +17,17 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
from eos.saveddata.ship import Ship
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Citadel(Ship):
def validate(self, item):
if item.category.name != "Structure":
+ pyfalog.error("Passed item '{0}' (category: {1}) is not under Structure category",item.name, item.category.name)
raise ValueError(
'Passed item "%s" (category: (%s)) is not under Structure category' % (item.name, item.category.name))
diff --git a/eos/saveddata/drone.py b/eos/saveddata/drone.py
index 9eaf9fc65..307d103a6 100644
--- a/eos/saveddata/drone.py
+++ b/eos/saveddata/drone.py
@@ -17,7 +17,7 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
from sqlalchemy.orm import validates, reconstructor
@@ -25,7 +25,7 @@ import eos.db
from eos.effectHandlerHelpers import HandledItem, HandledCharge
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
@@ -53,11 +53,11 @@ class Drone(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if self.itemID:
self.__item = eos.db.getItem(self.itemID)
if self.__item is None:
- logger.error("Item (id: %d) does not exist", self.itemID)
+ pyfalog.error("Item (id: %d) does not exist", self.itemID)
return
if self.isInvalid:
- logger.error("Item (id: %d) is not a Drone", self.itemID)
+ pyfalog.error("Item (id: %d) is not a Drone", self.itemID)
return
self.build()
diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py
index cc363ef0f..1051a187d 100644
--- a/eos/saveddata/fighter.py
+++ b/eos/saveddata/fighter.py
@@ -17,7 +17,7 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
from sqlalchemy.orm import validates, reconstructor
@@ -27,7 +27,7 @@ from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, C
from eos.saveddata.fighterAbility import FighterAbility
from eos.saveddata.module import Slot
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
@@ -61,11 +61,11 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if self.itemID:
self.__item = eos.db.getItem(self.itemID)
if self.__item is None:
- logger.error("Item (id: %d) does not exist", self.itemID)
+ pyfalog.error("Item (id: %d) does not exist", self.itemID)
return
if self.isInvalid:
- logger.error("Item (id: %d) is not a Fighter", self.itemID)
+ pyfalog.error("Item (id: %d) is not a Fighter", self.itemID)
return
self.build()
diff --git a/eos/saveddata/fighterAbility.py b/eos/saveddata/fighterAbility.py
index cb7c34912..54aad6f07 100644
--- a/eos/saveddata/fighterAbility.py
+++ b/eos/saveddata/fighterAbility.py
@@ -17,11 +17,11 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
from sqlalchemy.orm import reconstructor
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class FighterAbility(object):
@@ -59,7 +59,7 @@ class FighterAbility(object):
if self.effectID:
self.__effect = next((x for x in self.fighter.item.effects.itervalues() if x.ID == self.effectID), None)
if self.__effect is None:
- logger.error("Effect (id: %d) does not exist", self.effectID)
+ pyfalog.error("Effect (id: %d) does not exist", self.effectID)
return
self.build()
diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py
index 8241f9579..b275aef5a 100644
--- a/eos/saveddata/fit.py
+++ b/eos/saveddata/fit.py
@@ -33,9 +33,9 @@ from eos.saveddata.character import Character
from eos.saveddata.citadel import Citadel
from eos.saveddata.module import Module, State, Slot, Hardpoint
from utils.timer import Timer
-import logging
+from logbook import Logger
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class ImplantLocation(Enum):
@@ -84,7 +84,7 @@ class Fit(object):
if self.shipID:
item = eos.db.getItem(self.shipID)
if item is None:
- logger.error("Item (id: %d) does not exist", self.shipID)
+ pyfalog.error("Item (id: {0}) does not exist", self.shipID)
return
try:
@@ -97,7 +97,7 @@ class Fit(object):
# change all instances in source). Remove this at some point
self.extraAttributes = self.__ship.itemModifiedAttributes
except ValueError:
- logger.error("Item (id: %d) is not a Ship", self.shipID)
+ pyfalog.error("Item (id: {0}) is not a Ship", self.shipID)
return
if self.modeID and self.__ship:
@@ -448,7 +448,7 @@ class Fit(object):
self.commandBonuses[warfareBuffID] = (runTime, value, module, effect)
def __runCommandBoosts(self, runTime="normal"):
- logger.debug("Applying gang boosts for %r", self)
+ pyfalog.debug("Applying gang boosts for {0}", self)
for warfareBuffID in self.commandBonuses.keys():
# Unpack all data required to run effect properly
effect_runTime, value, thing, effect = self.commandBonuses[warfareBuffID]
@@ -630,21 +630,23 @@ class Fit(object):
del self.commandBonuses[warfareBuffID]
def calculateModifiedAttributes(self, targetFit=None, withBoosters=False, dirtyStorage=None):
- timer = Timer(u'Fit: {}, {}'.format(self.ID, self.name), logger)
- logger.debug("Starting fit calculation on: %r, withBoosters: %s", self, withBoosters)
+ # TODO: Validate that remooving this doesn't break anything
+ # TODO: Keywords: logbook logging Ebag
+ # timer = Timer(u'Fit: {}, {}'.format(self.ID, self.name), logger)
+ pyfalog.debug("Starting fit calculation on: {0}, withBoosters: {1}", self, withBoosters)
shadow = False
if targetFit and not withBoosters:
- logger.debug("Applying projections to target: %r", targetFit)
+ pyfalog.debug("Applying projections to target: {0}", targetFit)
projectionInfo = self.getProjectionInfo(targetFit.ID)
- logger.debug("ProjectionInfo: %s", projectionInfo)
+ pyfalog.debug("ProjectionInfo: {0}", projectionInfo)
if self == targetFit:
copied = self # original fit
shadow = True
# Don't inspect this, we genuinely want to reassign self
# noinspection PyMethodFirstArgAssignment
self = deepcopy(self)
- logger.debug("Handling self projection - making shadow copy of fit. %r => %r", copied, self)
+ pyfalog.debug("Handling self projection - making shadow copy of fit. {0} => {1}", copied, self)
# we delete the fit because when we copy a fit, flush() is
# called to properly handle projection updates. However, we do
# not want to save this fit to the database, so simply remove it
@@ -679,7 +681,7 @@ class Fit(object):
# projection have modifying stuff applied, such as gang boosts and other
# local modules that may help
if self.__calculated and not projected and not withBoosters:
- logger.debug("Fit has already been calculated and is not projected, returning: %r", self)
+ pyfalog.debug("Fit has already been calculated and is not projected, returning: {0}", self)
return
for runTime in ("early", "normal", "late"):
@@ -736,7 +738,8 @@ class Fit(object):
if not withBoosters and self.commandBonuses:
self.__runCommandBoosts(runTime)
- timer.checkpoint('Done with runtime: %s' % runTime)
+ # TODO: Tied with timer above
+ # timer.checkpoint('Done with runtime: %s' % runTime)
# Mark fit as calculated
self.__calculated = True
@@ -747,10 +750,11 @@ class Fit(object):
if fit.getProjectionInfo(self.ID).active:
fit.calculateModifiedAttributes(self, withBoosters=withBoosters, dirtyStorage=dirtyStorage)
- timer.checkpoint('Done with fit calculation')
+ # TODO: Tied with timer above
+ # timer.checkpoint('Done with fit calculation')
if shadow:
- logger.debug("Delete shadow fit object")
+ pyfalog.debug("Delete shadow fit object")
del self
def fill(self):
diff --git a/eos/saveddata/implant.py b/eos/saveddata/implant.py
index b2185542a..e7174f2ff 100644
--- a/eos/saveddata/implant.py
+++ b/eos/saveddata/implant.py
@@ -17,7 +17,7 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
from sqlalchemy.orm import validates, reconstructor
@@ -25,7 +25,7 @@ import eos.db
from eos.effectHandlerHelpers import HandledItem
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Implant(HandledItem, ItemAttrShortcut):
@@ -46,11 +46,11 @@ class Implant(HandledItem, ItemAttrShortcut):
if self.itemID:
self.__item = eos.db.getItem(self.itemID)
if self.__item is None:
- logger.error("Item (id: %d) does not exist", self.itemID)
+ pyfalog.error("Item (id: %d) does not exist", self.itemID)
return
if self.isInvalid:
- logger.error("Item (id: %d) is not an Implant", self.itemID)
+ pyfalog.error("Item (id: %d) is not an Implant", self.itemID)
return
self.build()
diff --git a/eos/saveddata/module.py b/eos/saveddata/module.py
index ba41d559d..55d8c7ed1 100644
--- a/eos/saveddata/module.py
+++ b/eos/saveddata/module.py
@@ -17,7 +17,7 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
from sqlalchemy.orm import validates, reconstructor
@@ -28,7 +28,7 @@ from eos.mathUtils import floorFloat
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut
from eos.saveddata.citadel import Citadel
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class State(Enum):
@@ -94,11 +94,11 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if self.itemID:
self.__item = eos.db.getItem(self.itemID)
if self.__item is None:
- logger.error("Item (id: %d) does not exist", self.itemID)
+ pyfalog.error("Item (id: %d) does not exist", self.itemID)
return
if self.isInvalid:
- logger.error("Item (id: %d) is not a Module", self.itemID)
+ pyfalog.error("Item (id: %d) is not a Module", self.itemID)
return
if self.chargeID:
diff --git a/eos/saveddata/override.py b/eos/saveddata/override.py
index c4f8a1e02..f3f84425d 100644
--- a/eos/saveddata/override.py
+++ b/eos/saveddata/override.py
@@ -17,14 +17,14 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
from sqlalchemy.orm import reconstructor
import eos.db
from eos.eqBase import EqBase
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Override(EqBase):
@@ -43,13 +43,13 @@ class Override(EqBase):
if self.attrID:
self.__attr = eos.db.getAttributeInfo(self.attrID)
if self.__attr is None:
- logger.error("Attribute (id: %d) does not exist", self.attrID)
+ pyfalog.error("Attribute (id: %d) does not exist", self.attrID)
return
if self.itemID:
self.__item = eos.db.getItem(self.itemID)
if self.__item is None:
- logger.error("Item (id: %d) does not exist", self.itemID)
+ pyfalog.error("Item (id: %d) does not exist", self.itemID)
return
@property
diff --git a/eos/saveddata/ship.py b/eos/saveddata/ship.py
index 4e4020cc7..1e3fd41f0 100644
--- a/eos/saveddata/ship.py
+++ b/eos/saveddata/ship.py
@@ -17,14 +17,14 @@
# along with eos. If not, see .
# ===============================================================================
-import logging
+from logbook import Logger
import eos.db
from eos.effectHandlerHelpers import HandledItem
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, cappingAttrKeyCache
from eos.saveddata.mode import Mode
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Ship(ItemAttrShortcut, HandledItem):
@@ -63,6 +63,7 @@ class Ship(ItemAttrShortcut, HandledItem):
def validate(self, item):
if item.category.name != "Ship":
+ pyfalog.error("Passed item '{0}' (category: {1}) is not under Ship category", item.name, item.category.name)
raise ValueError(
'Passed item "%s" (category: (%s)) is not under Ship category' % (item.name, item.category.name))
diff --git a/gui/bitmapLoader.py b/gui/bitmapLoader.py
index cb47e24bd..9ebfab114 100644
--- a/gui/bitmapLoader.py
+++ b/gui/bitmapLoader.py
@@ -27,6 +27,9 @@ import wx
import config
+from logbook import Logger
+logging = Logger(__name__)
+
try:
from collections import OrderedDict
except ImportError:
@@ -35,8 +38,10 @@ except ImportError:
class BitmapLoader(object):
try:
+ logging.info("Using zipped image files.")
archive = zipfile.ZipFile(config.getPyfaPath('imgs.zip'), 'r')
except IOError:
+ logging.info("Using local image files.")
archive = None
cachedBitmaps = OrderedDict()
diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py
index 2c6c926dc..1a6f81e48 100644
--- a/gui/builtinViews/fittingView.py
+++ b/gui/builtinViews/fittingView.py
@@ -33,7 +33,7 @@ from gui.builtinViewColumns.state import State
from gui.bitmapLoader import BitmapLoader
import gui.builtinViews.emptyView
from gui.utils.exportHtml import exportHtml
-from logging import getLogger
+from logbook import Logger
from gui.chromeTabs import EVT_NOTEBOOK_PAGE_CHANGED
from service.fit import Fit
@@ -41,7 +41,7 @@ from service.market import Market
import gui.globalEvents as GE
-logger = getLogger(__name__)
+pyfalog = Logger(__name__)
# Tab spawning handler
@@ -62,6 +62,7 @@ class FitSpawner(gui.multiSwitch.TabSpawner):
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=event.fitID))
break
except:
+ pyfalog.warning("Caught exception in fitSelected")
pass
if count < 0:
startup = getattr(event, "startup", False) # see OpenFitsThread in gui.mainFrame
@@ -278,6 +279,7 @@ class FittingView(d.Display):
sFit.refreshFit(self.getActiveFit())
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.activeFitID))
except wx._core.PyDeadObjectError:
+ pyfalog.warning("Caught dead object")
pass
event.Skip()
@@ -414,7 +416,7 @@ class FittingView(d.Display):
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit()))
else:
- logger.error("Missing module position for: %s", str(getattr(mod2, "ID", "Unknown")))
+ pyfalog.error("Missing module position for: {0}", str(getattr(mod2, "ID", "Unknown")))
def generateMods(self):
"""
@@ -483,7 +485,7 @@ class FittingView(d.Display):
self.Show(self.activeFitID is not None and self.activeFitID == event.fitID)
except wx._core.PyDeadObjectError:
- pass
+ pyfalog.warning("Caught dead object")
finally:
event.Skip()
@@ -637,14 +639,14 @@ class FittingView(d.Display):
try:
self.MakeSnapshot()
except:
- pass
+ pyfalog.warning("Failed to make snapshot")
def OnShow(self, event):
if event.GetShow():
try:
self.MakeSnapshot()
except:
- pass
+ pyfalog.warning("Failed to make snapshot")
event.Skip()
def Snapshot(self):
@@ -670,7 +672,7 @@ class FittingView(d.Display):
try:
fit = sFit.getFit(self.activeFitID)
except:
- return
+ pyfalog.warning("Failed to get fit")
if fit is None:
return
diff --git a/gui/characterEditor.py b/gui/characterEditor.py
index 1c7044f3e..8006fa56a 100644
--- a/gui/characterEditor.py
+++ b/gui/characterEditor.py
@@ -33,6 +33,8 @@ from service.fit import Fit
from service.character import Character
from service.network import AuthenticationError, TimeoutError
from service.market import Market
+from logbook import Logger
+pyfalog = Logger(__name__)
class CharacterTextValidor(BaseValidator):
@@ -55,6 +57,7 @@ class CharacterTextValidor(BaseValidator):
return True
except ValueError, e:
+ pyfalog.error(e)
wx.MessageBox(u"{}".format(e), "Error")
textCtrl.SetFocus()
return False
@@ -628,11 +631,16 @@ class APIView(wx.Panel):
try:
activeChar = self.charEditor.entityEditor.getActiveEntity()
list = sChar.apiCharList(activeChar.ID, self.inputID.GetLineText(0), self.inputKey.GetLineText(0))
- except AuthenticationError:
- self.stStatus.SetLabel("Authentication failure. Please check keyID and vCode combination.")
- except TimeoutError:
- self.stStatus.SetLabel("Request timed out. Please check network connectivity and/or proxy settings.")
+ except AuthenticationError, e:
+ msg = "Authentication failure. Please check keyID and vCode combination."
+ pyfalog.info(msg)
+ self.stStatus.SetLabel(msg)
+ except TimeoutError, e:
+ msg = "Request timed out. Please check network connectivity and/or proxy settings."
+ pyfalog.info(msg)
+ self.stStatus.SetLabel(msg)
except Exception, e:
+ pyfalog.error(e)
self.stStatus.SetLabel("Error:\n%s" % e.message)
else:
self.charChoice.Clear()
@@ -655,6 +663,7 @@ class APIView(wx.Panel):
sChar.apiFetch(activeChar.ID, charName)
self.stStatus.SetLabel("Successfully fetched %s\'s skills from EVE API." % charName)
except Exception, e:
+ pyfalog.error("Unable to retrieve {0}\'s skills. Error message:\n{1}", charName, e)
self.stStatus.SetLabel("Unable to retrieve %s\'s skills. Error message:\n%s" % (charName, e))
diff --git a/gui/characterSelection.py b/gui/characterSelection.py
index e85cd081b..d00026173 100644
--- a/gui/characterSelection.py
+++ b/gui/characterSelection.py
@@ -24,6 +24,8 @@ import gui.globalEvents as GE
import gui.mainFrame
from service.character import Character
from service.fit import Fit
+from logbook import Logger
+pyfalog = Logger(__name__)
class CharacterSelection(wx.Panel):
@@ -114,6 +116,7 @@ class CharacterSelection(wx.Panel):
sChar.apiFetch(self.getActiveCharacter(), charName)
except:
# can we do a popup, notifying user of API error?
+ pyfalog.error("API fetch error")
pass
self.refreshCharacterList()
diff --git a/gui/chromeTabs.py b/gui/chromeTabs.py
index 3265b8d8a..f052f28a6 100644
--- a/gui/chromeTabs.py
+++ b/gui/chromeTabs.py
@@ -25,9 +25,11 @@ import gui.utils.colorUtils as colorUtils
import gui.utils.drawUtils as drawUtils
import gui.utils.fonts as fonts
from gui.bitmapLoader import BitmapLoader
-
+from logbook import Logger
from service.fit import Fit
+pyfalog = Logger(__name__)
+
_PageChanging, EVT_NOTEBOOK_PAGE_CHANGING = wx.lib.newevent.NewEvent()
_PageChanged, EVT_NOTEBOOK_PAGE_CHANGED = wx.lib.newevent.NewEvent()
_PageAdding, EVT_NOTEBOOK_PAGE_ADDING = wx.lib.newevent.NewEvent()
@@ -1094,6 +1096,7 @@ class PFTabsContainer(wx.Panel):
self.previewTimer.Start(500, True)
break
except:
+ pyfalog.warning("Exception caught in CheckTabPreview.")
pass
def CheckAddHighlighted(self, x, y):
diff --git a/gui/contextMenu.py b/gui/contextMenu.py
index 7731c0120..848f02181 100644
--- a/gui/contextMenu.py
+++ b/gui/contextMenu.py
@@ -19,9 +19,9 @@
# noinspection PyPackageRequirements
import wx
-import logging
+from logbook import Logger
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class ContextMenu(object):
@@ -121,7 +121,7 @@ class ContextMenu(object):
debug_end = len(cls._ids)
if debug_end - debug_start:
- logger.debug("%d new IDs created for this menu" % (debug_end - debug_start))
+ pyfalog.debug("%d new IDs created for this menu" % (debug_end - debug_start))
return rootMenu if empty is False else None
diff --git a/gui/crestFittings.py b/gui/crestFittings.py
index 181841712..19e6a22b0 100644
--- a/gui/crestFittings.py
+++ b/gui/crestFittings.py
@@ -14,6 +14,9 @@ from eos.db import getItem
from gui.display import Display
import gui.globalEvents as GE
+from logbook import Logger
+pyfalog = Logger(__name__)
+
if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)):
from service.crest import Crest, CrestModes
@@ -147,7 +150,9 @@ class CrestFittings(wx.Frame):
self.fitTree.populateSkillTree(fittings)
del waitDialog
except requests.exceptions.ConnectionError:
- self.statusbar.SetStatusText("Connection error, please check your internet connection")
+ msg = "Connection error, please check your internet connection"
+ pyfalog.error(msg)
+ self.statusbar.SetStatusText(msg)
def importFitting(self, event):
selection = self.fitView.fitSelection
@@ -173,7 +178,9 @@ class CrestFittings(wx.Frame):
try:
sCrest.delFitting(self.getActiveCharacter(), data['fittingID'])
except requests.exceptions.ConnectionError:
- self.statusbar.SetStatusText("Connection error, please check your internet connection")
+ msg = "Connection error, please check your internet connection"
+ pyfalog.error(msg)
+ self.statusbar.SetStatusText(msg)
class ExportToEve(wx.Frame):
@@ -281,9 +288,12 @@ class ExportToEve(wx.Frame):
text = json.loads(res.text)
self.statusbar.SetStatusText(text['message'], 1)
except ValueError:
+ pyfalog.warning("Value error on loading JSON.")
self.statusbar.SetStatusText("", 1)
except requests.exceptions.ConnectionError:
- self.statusbar.SetStatusText("Connection error, please check your internet connection", 1)
+ msg = "Connection error, please check your internet connection"
+ pyfalog.error(msg)
+ self.statusbar.SetStatusText(msg)
class CrestMgmt(wx.Dialog):
@@ -406,6 +416,7 @@ class FittingsTreeView(wx.Panel):
cargo.amount = item['quantity']
list.append(cargo)
except:
+ pyfalog.error("Exception caught in displayFit")
pass
self.parent.fitView.fitSelection = selection
diff --git a/gui/graphFrame.py b/gui/graphFrame.py
index 843033c5b..1cf6e116d 100644
--- a/gui/graphFrame.py
+++ b/gui/graphFrame.py
@@ -18,7 +18,7 @@
# =============================================================================
import os
-import logging
+from logbook import Logger
import imp
# noinspection PyPackageRequirements
@@ -42,7 +42,7 @@ except ImportError:
mplImported = False
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class GraphFrame(wx.Frame):
@@ -73,7 +73,7 @@ class GraphFrame(wx.Frame):
self.legendFix = False
if not graphFrame_enabled:
- logger.info("Problems importing matplotlib; continuing without graphs")
+ pyfalog.info("Problems importing matplotlib; continuing without graphs")
return
try:
diff --git a/gui/mainFrame.py b/gui/mainFrame.py
index e2eb3a7c7..5cd31e83c 100644
--- a/gui/mainFrame.py
+++ b/gui/mainFrame.py
@@ -19,7 +19,7 @@
import sys
import os.path
-import logging
+from logbook import Logger
import sqlalchemy
# noinspection PyPackageRequirements
@@ -94,7 +94,7 @@ if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION
print("Error loading Attribute Editor: %s.\nAccess to Attribute Editor is disabled." % e.message)
disableOverrideEditor = True
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
# dummy panel(no paint no erasebk)
@@ -145,6 +145,7 @@ class MainFrame(wx.Frame):
return cls.__instance if cls.__instance is not None else MainFrame()
def __init__(self, title="pyfa"):
+ pyfalog.debug("Initialize MainFrame")
self.title = title
wx.Frame.__init__(self, None, wx.ID_ANY, self.title)
@@ -399,7 +400,7 @@ class MainFrame(wx.Frame):
try:
dlg.Destroy()
except PyDeadObjectError:
- logger.error("Tried to destroy an object that doesn't exist in .")
+ pyfalog.error("Tried to destroy an object that doesn't exist in .")
def showImplantSetEditor(self, event):
ImplantSetEditorDlg(self)
@@ -427,7 +428,7 @@ class MainFrame(wx.Frame):
try:
dlg.Destroy()
except PyDeadObjectError:
- logger.error("Tried to destroy an object that doesn't exist in .")
+ pyfalog.error("Tried to destroy an object that doesn't exist in .")
return
with open(path, "w", encoding="utf-8") as openfile:
@@ -437,7 +438,7 @@ class MainFrame(wx.Frame):
try:
dlg.Destroy()
except PyDeadObjectError:
- logger.error("Tried to destroy an object that doesn't exist in .")
+ pyfalog.error("Tried to destroy an object that doesn't exist in .")
def showPreferenceDialog(self, event):
dlg = PreferenceDialog(self)
@@ -734,7 +735,7 @@ class MainFrame(wx.Frame):
try:
fits = Port().importFitFromBuffer(clipboard, self.getActiveFit())
except:
- logger.error("Attempt to import failed:\n%s", clipboard)
+ pyfalog.error("Attempt to import failed:\n{0}", clipboard)
else:
self._openAfterImport(fits)
@@ -754,7 +755,7 @@ class MainFrame(wx.Frame):
try:
dlg.Destroy()
except PyDeadObjectError:
- logger.error("Tried to destroy an object that doesn't exist in .")
+ pyfalog.error("Tried to destroy an object that doesn't exist in .")
def exportSkillsNeeded(self, event):
""" Exports skills needed for active fit and active character """
@@ -811,7 +812,7 @@ class MainFrame(wx.Frame):
try:
dlg.Destroy()
except PyDeadObjectError:
- logger.error("Tried to destroy an object that doesn't exist in .")
+ pyfalog.error("Tried to destroy an object that doesn't exist in .")
def backupToXml(self, event):
""" Back up all fits to EVE XML file """
diff --git a/gui/mainMenuBar.py b/gui/mainMenuBar.py
index a9b42cb4b..00402a7a3 100644
--- a/gui/mainMenuBar.py
+++ b/gui/mainMenuBar.py
@@ -26,6 +26,9 @@ import gui.graphFrame
import gui.globalEvents as GE
from gui.bitmapLoader import BitmapLoader
+from logbook import Logger
+pyfalog = Logger(__name__)
+
if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)):
from service.crest import Crest
from service.crest import CrestModes
@@ -33,6 +36,7 @@ if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION
class MainMenuBar(wx.MenuBar):
def __init__(self, mainFrame):
+ pyfalog.debug("Initialize MainMenuBar")
self.characterEditorId = wx.NewId()
self.damagePatternEditorId = wx.NewId()
self.targetResistsEditorId = wx.NewId()
@@ -166,6 +170,7 @@ class MainMenuBar(wx.MenuBar):
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
def fitChanged(self, event):
+ pyfalog.debug("fitChanged triggered")
enable = event.fitID is not None
self.Enable(wx.ID_SAVEAS, enable)
self.Enable(wx.ID_COPY, enable)
diff --git a/gui/marketBrowser.py b/gui/marketBrowser.py
index 0ee1b008b..0afb2b3b4 100644
--- a/gui/marketBrowser.py
+++ b/gui/marketBrowser.py
@@ -26,6 +26,9 @@ import gui.PFSearchBox as SBox
from gui.cachingImageList import CachingImageList
from gui.contextMenu import ContextMenu
from gui.bitmapLoader import BitmapLoader
+from logbook import Logger
+
+pyfalog = Logger(__name__)
ItemSelected, ITEM_SELECTED = wx.lib.newevent.NewEvent()
@@ -56,6 +59,7 @@ class MetaButton(wx.ToggleButton):
class MarketBrowser(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
+ pyfalog.debug("Initialize marketBrowser")
vbox = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(vbox)
@@ -134,6 +138,7 @@ class SearchBox(SBox.PFSearchBox):
class MarketTree(wx.TreeCtrl):
def __init__(self, parent, marketBrowser):
wx.TreeCtrl.__init__(self, parent, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
+ pyfalog.debug("Initialize marketTree")
self.root = self.AddRoot("root")
self.imageList = CachingImageList(16, 16)
@@ -183,6 +188,7 @@ class MarketTree(wx.TreeCtrl):
try:
childId = self.AppendItem(root, childMktGrp.name, iconId, data=wx.TreeItemData(childMktGrp.ID))
except:
+ pyfalog.debug("Error appending item.")
continue
if sMkt.marketGroupHasTypesCheck(childMktGrp) is False:
self.AppendItem(childId, "dummy")
@@ -226,6 +232,7 @@ class ItemView(Display):
def __init__(self, parent, marketBrowser):
Display.__init__(self, parent)
+ pyfalog.debug("Initialize ItemView")
marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.selectionMade)
self.unfilteredStore = set()
@@ -252,6 +259,7 @@ class ItemView(Display):
self.metaMap = self.makeReverseMetaMap()
# Fill up recently used modules set
+ pyfalog.debug("Fill up recently used modules set")
for itemID in self.sMkt.serviceMarketRecentlyUsedModules["pyfaMarketRecentlyUsedModules"]:
self.recentlyUsedModules.add(self.sMkt.getItem(itemID))
diff --git a/gui/patternEditor.py b/gui/patternEditor.py
index ed63fd9a3..879683373 100644
--- a/gui/patternEditor.py
+++ b/gui/patternEditor.py
@@ -25,6 +25,9 @@ from wx.lib.intctrl import IntCtrl
from gui.utils.clipboard import toClipboard, fromClipboard
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
from service.damagePattern import DamagePattern, ImportError
+from logbook import Logger
+
+pyfalog = Logger(__name__)
class DmgPatternTextValidor(BaseValidator):
@@ -47,6 +50,7 @@ class DmgPatternTextValidor(BaseValidator):
return True
except ValueError as e:
+ pyfalog.error(e)
wx.MessageBox(u"{}".format(e), "Error")
textCtrl.SetFocus()
return False
@@ -256,9 +260,13 @@ class DmgPatternEditorDlg(wx.Dialog):
sDP.importPatterns(text)
self.stNotice.SetLabel("Patterns successfully imported from clipboard")
except ImportError as e:
+ pyfalog.error(e)
self.stNotice.SetLabel(str(e))
- except Exception:
- self.stNotice.SetLabel("Could not import from clipboard: unknown errors")
+ except Exception as e:
+ msg = "Could not import from clipboard: unknown errors"
+ pyfalog.warning(msg)
+ pyfalog.error(e)
+ self.stNotice.SetLabel(msg)
finally:
self.entityEditor.refreshEntityList()
else:
diff --git a/gui/propertyEditor.py b/gui/propertyEditor.py
index 81a305a11..3416d591a 100644
--- a/gui/propertyEditor.py
+++ b/gui/propertyEditor.py
@@ -1,5 +1,5 @@
import csv
-import logging
+from logbook import Logger
# noinspection PyPackageRequirements
import wx
@@ -21,7 +21,7 @@ import gui.PFSearchBox as SBox
from gui.marketBrowser import SearchBox
from gui.bitmapLoader import BitmapLoader
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class AttributeEditor(wx.Frame):
@@ -270,7 +270,7 @@ class AttributeGrid(wxpg.PropertyGrid):
self.itemView.updateItems()
- logger.debug('%s changed to "%s"' % (p.GetName(), p.GetValueAsString()))
+ pyfalog.debug('{0} changed to "{1}"', p.GetName(), p.GetValueAsString())
def OnPropGridSelect(self, event):
pass
diff --git a/gui/resistsEditor.py b/gui/resistsEditor.py
index 7e5e3cd62..c8bab84bb 100644
--- a/gui/resistsEditor.py
+++ b/gui/resistsEditor.py
@@ -23,6 +23,9 @@ from service.targetResists import TargetResists
from gui.bitmapLoader import BitmapLoader
from gui.utils.clipboard import toClipboard, fromClipboard
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
+from logbook import Logger
+
+pyfalog = Logger(__name__)
class TargetResistsTextValidor(BaseValidator):
@@ -45,6 +48,7 @@ class TargetResistsTextValidor(BaseValidator):
return True
except ValueError as e:
+ pyfalog.error(e)
wx.MessageBox(u"{}".format(e), "Error")
textCtrl.SetFocus()
return False
@@ -230,10 +234,14 @@ class ResistsEditorDlg(wx.Dialog):
except ValueError:
editObj.SetForegroundColour(wx.RED)
- self.stNotice.SetLabel("Incorrect Formatting (decimals only)")
+ msg = "Incorrect Formatting (decimals only)"
+ pyfalog.warning(msg)
+ self.stNotice.SetLabel(msg)
except AssertionError:
editObj.SetForegroundColour(wx.RED)
- self.stNotice.SetLabel("Incorrect Range (must be 0-100)")
+ msg = "Incorrect Range (must be 0-100)"
+ pyfalog.warning(msg)
+ self.stNotice.SetLabel(msg)
finally: # Refresh for color changes to take effect immediately
self.Refresh()
@@ -271,9 +279,13 @@ class ResistsEditorDlg(wx.Dialog):
sTR.importPatterns(text)
self.stNotice.SetLabel("Patterns successfully imported from clipboard")
except ImportError as e:
+ pyfalog.error(e)
self.stNotice.SetLabel(str(e))
- except Exception:
- self.stNotice.SetLabel("Could not import from clipboard: unknown errors")
+ except Exception as e:
+ msg = "Could not import from clipboard:"
+ pyfalog.warning(msg)
+ pyfalog.error(e)
+ self.stNotice.SetLabel(msg)
finally:
self.entityEditor.refreshEntityList()
else:
diff --git a/gui/setEditor.py b/gui/setEditor.py
index 036444e18..d199c1cc2 100644
--- a/gui/setEditor.py
+++ b/gui/setEditor.py
@@ -17,7 +17,7 @@
# along with pyfa. If not, see .
# =============================================================================
-import logging
+from logbook import Logger
# noinspection PyPackageRequirements
import wx
@@ -26,7 +26,7 @@ from gui.builtinViews.implantEditor import BaseImplantEditorView
from gui.utils.clipboard import toClipboard, fromClipboard
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class ImplantTextValidor(BaseValidator):
@@ -49,6 +49,7 @@ class ImplantTextValidor(BaseValidator):
return True
except ValueError as e:
+ pyfalog.error(e)
wx.MessageBox(u"{}".format(e), "Error")
textCtrl.SetFocus()
return False
@@ -198,9 +199,10 @@ class ImplantSetEditorDlg(wx.Dialog):
self.stNotice.SetLabel("Patterns successfully imported from clipboard")
self.showInput(False)
except ImportError as e:
+ pyfalog.error(e)
self.stNotice.SetLabel(str(e))
except Exception as e:
- logging.exception("Unhandled Exception")
+ pyfalog.error(e)
self.stNotice.SetLabel("Could not import from clipboard: unknown errors")
finally:
self.updateChoices()
diff --git a/gui/shipBrowser.py b/gui/shipBrowser.py
index 9822c699d..466e02e34 100644
--- a/gui/shipBrowser.py
+++ b/gui/shipBrowser.py
@@ -21,6 +21,8 @@ import gui.utils.animEffects as animEffects
from gui.PFListPane import PFListPane
from gui.contextMenu import ContextMenu
from gui.bitmapLoader import BitmapLoader
+from logbook import Logger
+pyfalog = Logger(__name__)
FitRenamed, EVT_FIT_RENAMED = wx.lib.newevent.NewEvent()
FitSelected, EVT_FIT_SELECTED = wx.lib.newevent.NewEvent()
@@ -682,6 +684,7 @@ class ShipBrowser(wx.Panel):
self.lpane.Freeze()
self.lpane.RemoveAllChildren()
+ pyfalog.debug("Populate ship category list.")
if len(self.categoryList) == 0:
# set cache of category list
self.categoryList = list(sMkt.getShipRoot())
diff --git a/gui/utils/exportHtml.py b/gui/utils/exportHtml.py
index 802a8358b..8e4fd3ad2 100644
--- a/gui/utils/exportHtml.py
+++ b/gui/utils/exportHtml.py
@@ -5,6 +5,9 @@ import wx
from service.settings import HTMLExportSettings
from service.fit import Fit
from service.market import Market
+from logbook import Logger
+
+pyfalog = Logger(__name__)
class exportHtml(object):
@@ -196,6 +199,7 @@ class exportHtmlThread(threading.Thread):
HTMLgroup += ' ' + ship.name + ": " + \
fit[1] + '\n'
except:
+ pyfalog.warning("Failed to export line")
pass
finally:
if self.callback:
@@ -218,6 +222,7 @@ class exportHtmlThread(threading.Thread):
HTMLship += ' ' + fit[
1] + '\n'
except:
+ pyfalog.warning("Failed to export line")
continue
finally:
if self.callback:
@@ -270,6 +275,7 @@ class exportHtmlThread(threading.Thread):
HTML += '' + ship.name + ': ' + \
fit[1] + '
\n'
except:
+ pyfalog.error("Failed to export line")
continue
finally:
if self.callback:
diff --git a/pyfa.py b/pyfa.py
index 6453d373e..6526e4f18 100755
--- a/pyfa.py
+++ b/pyfa.py
@@ -19,11 +19,17 @@
# ==============================================================================
import sys
+import os
+import os.path
import re
import config
from optparse import OptionParser, BadOptionError, AmbiguousOptionError
+from logbook import TimedRotatingFileHandler, Logger, StreamHandler, NestedSetup, FingersCrossedHandler, NullHandler, \
+ CRITICAL, ERROR, WARNING, DEBUG, INFO
+pyfalog = Logger(__name__)
+
class PassThroughOptionParser(OptionParser):
"""
@@ -36,9 +42,29 @@ class PassThroughOptionParser(OptionParser):
try:
OptionParser._process_args(self, largs, rargs, values)
except (BadOptionError, AmbiguousOptionError) as e:
+ pyfalog.error("Bad startup option passed.")
largs.append(e.opt_str)
+class LoggerWriter:
+ def __init__(self, level):
+ # self.level is really like using log.debug(message)
+ # at least in my case
+ self.level = level
+
+ def write(self, message):
+ # if statement reduces the amount of newlines that are
+ # printed to the logger
+ if message not in {'\n', ' '}:
+ self.level(message.replace("\n", ""))
+
+ def flush(self):
+ # create a flush method so things can be flushed when
+ # the system wants to. Not sure if simply 'printing'
+ # sys.stderr is the correct way to do it, but it seemed
+ # to work properly for me.
+ self.level(sys.stderr)
+
# Parse command line options
usage = "usage: %prog [--root]"
parser = PassThroughOptionParser(usage=usage)
@@ -47,9 +73,23 @@ parser.add_option("-w", "--wx28", action="store_true", dest="force28", help="For
parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Set logger to debug level.", default=False)
parser.add_option("-t", "--title", action="store", dest="title", help="Set Window Title", default=None)
parser.add_option("-s", "--savepath", action="store", dest="savepath", help="Set the folder for savedata", default=None)
+parser.add_option("-l", "--logginglevel", action="store", dest="logginglevel", help="Set the desired logging level (Critical, Error, Warning, Info, Debug)", default="Error")
(options, args) = parser.parse_args()
+if options.logginglevel == "Critical":
+ options.logginglevel = CRITICAL
+elif options.logginglevel == "Error":
+ options.logginglevel = ERROR
+elif options.logginglevel == "Warning":
+ options.logginglevel = WARNING
+elif options.logginglevel == "Info":
+ options.logginglevel = INFO
+elif options.logginglevel == "Debug":
+ options.logginglevel = DEBUG
+else:
+ options.logginglevel = ERROR
+
if not hasattr(sys, 'frozen'):
if sys.version_info < (2, 6) or sys.version_info > (3, 0):
@@ -120,26 +160,119 @@ if __name__ == "__main__":
config.defPaths(options.savepath)
# Basic logging initialization
- import logging
- logging.basicConfig()
- # Import everything
- # noinspection PyPackageRequirements
- import wx
- import os
- import os.path
+ # Logging levels:
+ '''
+ logbook.CRITICAL
+ logbook.ERROR
+ logbook.WARNING
+ logbook.INFO
+ logbook.DEBUG
+ logbook.NOTSET
+ '''
- import eos.db
- # noinspection PyUnresolvedReferences
- import service.prefetch # noqa: F401
- from gui.mainFrame import MainFrame
+ if options.debug:
+ savePath_filename = "Pyfa_debug.log"
+ else:
+ savePath_filename = "Pyfa.log"
- # Make sure the saveddata db exists
- if not os.path.exists(config.savePath):
- os.mkdir(config.savePath)
+ savePath_Destination = config.getSavePath(savePath_filename)
- eos.db.saveddata_meta.create_all()
+ try:
+ if options.debug:
+ logging_mode = "Debug"
+ logging_setup = NestedSetup([
+ # make sure we never bubble up to the stderr handler
+ # if we run out of setup handling
+ NullHandler(),
+ StreamHandler(
+ sys.stdout,
+ bubble=False,
+ level=options.logginglevel
+ ),
+ TimedRotatingFileHandler(
+ savePath_Destination,
+ level=0,
+ backup_count=3,
+ bubble=True,
+ date_format='%Y-%m-%d',
+ ),
+ ])
+ else:
+ logging_mode = "User"
+ logging_setup = NestedSetup([
+ # make sure we never bubble up to the stderr handler
+ # if we run out of setup handling
+ NullHandler(),
+ FingersCrossedHandler(
+ TimedRotatingFileHandler(
+ savePath_Destination,
+ level=0,
+ backup_count=3,
+ bubble=False,
+ date_format='%Y-%m-%d',
+ ),
+ action_level=ERROR,
+ buffer_size=1000,
+ # pull_information=True,
+ # reset=False,
+ )
+ ])
+ except:
+ logging_mode = "Console Only"
+ logging_setup = NestedSetup([
+ # make sure we never bubble up to the stderr handler
+ # if we run out of setup handling
+ NullHandler(),
+ StreamHandler(
+ sys.stdout,
+ bubble=False
+ )
+ ])
- pyfa = wx.App(False)
- MainFrame(options.title)
- pyfa.MainLoop()
+ with logging_setup.threadbound():
+ # Don't redirect if frozen
+ if not hasattr(sys, 'frozen') and not options.debug:
+ # Output all stdout (print) messages as warnings
+ try:
+ sys.stdout = LoggerWriter(pyfalog.warning)
+ except ValueError, Exception:
+ pyfalog.critical("Cannot access log file. Continuing without writing stdout to log.")
+ # Output all stderr (stacktrace) messages as critical
+ try:
+ sys.stderr = LoggerWriter(pyfalog.critical)
+ except ValueError, Exception:
+ pyfalog.critical("Cannot access log file. Continuing without writing stderr to log.")
+
+ pyfalog.info("Starting Pyfa")
+ pyfalog.info("Running in logging mode: {0}", logging_mode)
+
+ if hasattr(sys, 'frozen') and options.debug:
+ pyfalog.critical("Running in frozen mode with debug turned on. Forcing all output to be written to log.")
+
+ # Import everything
+ pyfalog.debug("Import wx")
+ # noinspection PyPackageRequirements
+ import wx
+
+ pyfalog.debug("Import eos.db")
+ import eos.db
+
+ pyfalog.debug("Run prefetch")
+ # noinspection PyUnresolvedReferences
+ import service.prefetch # noqa: F401
+
+ if not os.path.exists(config.savePath):
+ pyfalog.debug("Saveddata path does not exist, creating new path")
+ os.mkdir(config.savePath)
+ else:
+ pyfalog.debug("Using existing saveddata path: {0}", config.savePath)
+
+ eos.db.saveddata_meta.create_all()
+
+ pyfa = wx.App(False)
+ pyfalog.debug("Show GUI")
+ from gui.mainFrame import MainFrame
+ MainFrame(options.title)
+ pyfalog.debug("Run MainLoop()")
+ pyfa.MainLoop()
diff --git a/requirements.txt b/requirements.txt
index 2d8894113..ed301fe25 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
+logbook
matplotlib
PyYAML
python-dateutil
diff --git a/service/character.py b/service/character.py
index 830eb5d57..dba74b2cb 100644
--- a/service/character.py
+++ b/service/character.py
@@ -20,7 +20,7 @@
import copy
import itertools
import json
-import logging
+from logbook import Logger
import threading
from codecs import open
from xml.etree import ElementTree
@@ -39,7 +39,7 @@ from eos.saveddata.character import Character as es_Character
from eos.saveddata.module import Slot as es_Slot, Module as es_Module
from eos.saveddata.fighter import Fighter as es_Fighter
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class CharacterImportThread(threading.Thread):
@@ -72,7 +72,7 @@ class CharacterImportThread(threading.Thread):
charFile = open(path, mode='r').read()
doc = minidom.parseString(charFile)
if doc.documentElement.tagName not in ("SerializableCCPCharacter", "SerializableUriCharacter"):
- logger.error("Incorrect EVEMon XML sheet")
+ pyfalog.error("Incorrect EVEMon XML sheet")
raise RuntimeError("Incorrect EVEMon XML sheet")
name = doc.getElementsByTagName("name")[0].firstChild.nodeValue
skill_els = doc.getElementsByTagName("skill")
@@ -84,7 +84,7 @@ class CharacterImportThread(threading.Thread):
"level": int(skill.getAttribute("level")),
})
else:
- logger.error("Attempted to import unknown skill %s (ID: %s) (Level: %s)",
+ pyfalog.error("Attempted to import unknown skill %s (ID: %s) (Level: %s)",
skill.getAttribute("name"),
skill.getAttribute("typeID"),
skill.getAttribute("level"),
@@ -92,8 +92,8 @@ class CharacterImportThread(threading.Thread):
char = sCharacter.new(name + " (EVEMon)")
sCharacter.apiUpdateCharSheet(char.ID, skills)
except Exception, e:
- logger.error("Exception on character import:")
- logger.error(e)
+ pyfalog.error("Exception on character import:")
+ pyfalog.error(e)
continue
wx.CallAfter(self.callback)
@@ -304,7 +304,7 @@ class Character(object):
@staticmethod
def rename(char, newName):
if char.name in ("All 0", "All 5"):
- logger.info("Cannot rename built in characters.")
+ pyfalog.info("Cannot rename built in characters.")
else:
char.name = newName
eos.db.commit()
@@ -404,7 +404,7 @@ class Character(object):
def addImplant(charID, itemID):
char = eos.db.getCharacter(charID)
if char.ro:
- logger.error("Trying to add implant to read-only character")
+ pyfalog.error("Trying to add implant to read-only character")
return
implant = es_Implant(eos.db.getItem(itemID))
diff --git a/service/crest.py b/service/crest.py
index 39863fb31..c372365e6 100644
--- a/service/crest.py
+++ b/service/crest.py
@@ -1,7 +1,7 @@
# noinspection PyPackageRequirements
import wx
import thread
-import logging
+from logbook import Logger
import threading
import copy
import uuid
@@ -15,7 +15,7 @@ from service.settings import CRESTSettings
from service.server import StoppableHTTPServer, AuthHandler
from service.pycrest.eve import EVE
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Servers(Enum):
@@ -153,17 +153,17 @@ class Crest(object):
def logout(self):
"""Logout of implicit character"""
- logging.debug("Character logout")
+ pyfalog.debug("Character logout")
self.implicitCharacter = None
wx.PostEvent(self.mainFrame, GE.SsoLogout(type=self.settings.get('mode')))
def stopServer(self):
- logging.debug("Stopping Server")
+ pyfalog.debug("Stopping Server")
self.httpd.stop()
self.httpd = None
def startServer(self):
- logging.debug("Starting server")
+ pyfalog.debug("Starting server")
if self.httpd:
self.stopServer()
time.sleep(1)
@@ -179,10 +179,10 @@ class Crest(object):
return
if message['state'][0] != self.state:
- logger.warn("OAUTH state mismatch")
+ pyfalog.warn("OAUTH state mismatch")
return
- logger.debug("Handling CREST login with: %s" % message)
+ pyfalog.debug("Handling CREST login with: %s" % message)
if 'access_token' in message: # implicit
eve = copy.deepcopy(self.eve)
@@ -196,7 +196,7 @@ class Crest(object):
eve()
info = eve.whoami()
- logger.debug("Got character info: %s" % info)
+ pyfalog.debug("Got character info: %s" % info)
self.implicitCharacter = CrestChar(info['CharacterID'], info['CharacterName'])
self.implicitCharacter.eve = eve
@@ -209,7 +209,7 @@ class Crest(object):
eve()
info = eve.whoami()
- logger.debug("Got character info: %s" % info)
+ pyfalog.debug("Got character info: %s" % info)
# check if we have character already. If so, simply replace refresh_token
char = self.getCrestCharacter(int(info['CharacterID']))
diff --git a/service/fit.py b/service/fit.py
index bbd6fb334..c0bbfad62 100644
--- a/service/fit.py
+++ b/service/fit.py
@@ -18,7 +18,7 @@
# ===============================================================================
import copy
-import logging
+from logbook import Logger
import eos.db
from eos.saveddata.booster import Booster as es_Booster
@@ -36,7 +36,7 @@ from service.character import Character
from service.damagePattern import DamagePattern
from service.settings import SettingsProvider
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
class Fit(object):
@@ -50,6 +50,7 @@ class Fit(object):
return cls.instance
def __init__(self):
+ pyfalog.debug("Initialize Fit class")
self.pattern = DamagePattern.getInstance().getDamagePattern("Uniform")
self.targetResists = None
self.character = saveddata_Character.getAll5()
@@ -1010,7 +1011,7 @@ class Fit(object):
self.recalc(fit)
def recalc(self, fit, withBoosters=True):
- logger.debug("=" * 10 + "recalc" + "=" * 10)
+ pyfalog.debug("=" * 10 + "recalc" + "=" * 10)
if fit.factorReload is not self.serviceFittingOptions["useGlobalForceReload"]:
fit.factorReload = self.serviceFittingOptions["useGlobalForceReload"]
fit.clear()
diff --git a/service/market.py b/service/market.py
index 8a2abb107..287d84929 100644
--- a/service/market.py
+++ b/service/market.py
@@ -19,7 +19,7 @@
import re
import threading
-import logging
+from logbook import Logger
import Queue
# noinspection PyPackageRequirements
@@ -41,7 +41,7 @@ try:
except ImportError:
from utils.compat import OrderedDict
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
# Event which tells threads dependent on Market that it's initialized
mktRdy = threading.Event()
@@ -74,12 +74,12 @@ class ShipBrowserWorkerThread(threading.Thread):
wx.CallAfter(callback, (id_, set_))
except:
- pass
+ pyfalog.debug("Callback failed.")
finally:
try:
queue.task_done()
except:
- pass
+ pyfalog.debug("Queue task done failed.")
class PriceWorkerThread(threading.Thread):
@@ -88,9 +88,11 @@ class PriceWorkerThread(threading.Thread):
self.name = "PriceWorker"
def run(self):
+ pyfalog.debug("Run start")
self.queue = Queue.Queue()
self.wait = {}
self.processUpdates()
+ pyfalog.debug("Run end")
def processUpdates(self):
queue = self.queue
@@ -440,7 +442,7 @@ class Market(object):
else:
raise TypeError("Need Item object, integer, float or string as argument")
except:
- logger.error("Could not get item: %s", identity)
+ pyfalog.error("Could not get item: %s", identity)
raise
return item
@@ -834,7 +836,7 @@ class Market(object):
try:
callback(requests)
except Exception:
- pass
+ pyfalog.debug("Callback failed.")
eos.db.commit()
self.priceWorkerThread.trigger(requests, cb)
@@ -850,7 +852,7 @@ class Market(object):
try:
callback(item)
except:
- pass
+ pyfalog.debug("Callback failed.")
self.priceWorkerThread.setToWait(item.ID, cb)
diff --git a/service/port.py b/service/port.py
index 5a6b53fb5..5e182f38e 100644
--- a/service/port.py
+++ b/service/port.py
@@ -20,7 +20,7 @@
import re
import os
import xml.dom
-import logging
+from logbook import Logger
import collections
import json
import threading
@@ -50,7 +50,7 @@ from service.market import Market
if 'wxMac' not in wx.PlatformInfo or ('wxMac' in wx.PlatformInfo and wx.VERSION >= (3, 0)):
from service.crest import Crest
-logger = logging.getLogger("pyfa.service.port")
+pyfalog = Logger(__name__)
try:
from collections import OrderedDict
@@ -134,21 +134,21 @@ class Port(object):
savebom = bom
if codec_found is None:
- logger.info("Unicode BOM not found in file %s.", path)
+ pyfalog.info("Unicode BOM not found in file %s.", path)
attempt_codecs = (defcodepage, "utf-8", "utf-16", "cp1252")
for page in attempt_codecs:
try:
- logger.info("Attempting to decode file %s using %s page.", path, page)
+ pyfalog.info("Attempting to decode file %s using %s page.", path, page)
srcString = unicode(srcString, page)
codec_found = page
- logger.info("File %s decoded using %s page.", path, page)
+ pyfalog.info("File %s decoded using %s page.", path, page)
except UnicodeDecodeError:
- logger.info("Error unicode decoding %s from page %s, trying next codec", path, page)
+ pyfalog.info("Error unicode decoding %s from page %s, trying next codec", path, page)
else:
break
else:
- logger.info("Unicode BOM detected in %s, using %s page.", path, codec_found)
+ pyfalog.info("Unicode BOM detected in %s, using %s page.", path, codec_found)
srcString = unicode(srcString[len(savebom):], codec_found)
else:
@@ -167,7 +167,7 @@ class Port(object):
except xml.parsers.expat.ExpatError:
return False, "Malformed XML in %s" % path
except Exception:
- logger.exception("Unknown exception processing: %s", path)
+ pyfalog.exception("Unknown exception processing: %s", path)
return False, "Unknown Error while processing %s" % path
IDs = []
@@ -340,6 +340,7 @@ class Port(object):
except ValueError:
f.ship = Citadel(sMkt.getItem(fit['ship']['id']))
except:
+ pyfalog.warning("Caught exception in importCrest")
return None
items = fit['items']
@@ -365,6 +366,7 @@ class Port(object):
m = Module(item)
# When item can't be added to any slot (unknown item or just charge), ignore it
except ValueError:
+ pyfalog.debug("Item can't be added to any slot (unknown item or just charge)")
continue
# Add subsystems before modules to make sure T3 cruisers have subsystems installed
if item.category.name == "Subsystem":
@@ -377,6 +379,7 @@ class Port(object):
moduleList.append(m)
except:
+ pyfalog.warning("Could not process module.")
continue
# Recalc to get slot numbers correct for T3 cruisers
@@ -405,6 +408,7 @@ class Port(object):
string = string[string.index(str(id_)):]
break
except:
+ pyfalog.warning("Exception caught in importDna")
pass
string = string[:string.index("::") + 2]
info = string.split(":")
@@ -422,7 +426,7 @@ class Port(object):
return s_[:10] + "..."
return s_
- logger.exception("Couldn't import ship data %r", [logtransform(s) for s in info])
+ pyfalog.exception("Couldn't import ship data {0}", [logtransform(s) for s in info])
return None
moduleList = []
@@ -449,6 +453,7 @@ class Port(object):
try:
m = Module(item)
except:
+ pyfalog.warning("Exception caught in importDna")
continue
# Add subsystems before modules to make sure T3 cruisers have subsystems installed
if item.category.name == "Subsystem":
@@ -497,6 +502,7 @@ class Port(object):
fit.ship = Citadel(ship)
fit.name = fitName
except:
+ pyfalog.warning("Exception caught in importEft")
return
# maintain map of drones and their quantities
@@ -537,6 +543,7 @@ class Port(object):
item = sMkt.getItem(modName, eager="group.category")
except:
# if no data can be found (old names)
+ pyfalog.warning("no data can be found (old names)")
continue
if item.category.name == "Drone":
@@ -563,7 +570,7 @@ class Port(object):
elif "boosterness" in item.attributes:
fit.boosters.append(Booster(item))
else:
- logger.error("Failed to import implant: %s", line)
+ pyfalog.error("Failed to import implant: {0}", line)
# elif item.category.name == "Subsystem":
# try:
# subsystem = Module(item)
@@ -689,6 +696,7 @@ class Port(object):
try:
droneItem = sMkt.getItem(droneName, eager="group.category")
except:
+ pyfalog.warning("Cannot get item.")
continue
if droneItem.category.name == "Drone":
# Add drone to the fitting
@@ -710,6 +718,7 @@ class Port(object):
try:
implantItem = sMkt.getItem(entityData, eager="group.category")
except:
+ pyfalog.warning("Cannot get item.")
continue
if implantItem.category.name != "Implant":
continue
@@ -725,6 +734,7 @@ class Port(object):
try:
boosterItem = sMkt.getItem(entityData, eager="group.category")
except:
+ pyfalog.warning("Cannot get item.")
continue
# All boosters have implant category
if boosterItem.category.name != "Implant":
@@ -745,6 +755,7 @@ class Port(object):
try:
item = sMkt.getItem(cargoName)
except:
+ pyfalog.warning("Cannot get item.")
continue
# Add Cargo to the fitting
c = Cargo(item)
@@ -758,6 +769,7 @@ class Port(object):
try:
modItem = sMkt.getItem(modName)
except:
+ pyfalog.warning("Cannot get item.")
continue
# Create module
@@ -779,6 +791,7 @@ class Port(object):
if chargeItem.category.name == "Charge":
m.charge = chargeItem
except:
+ pyfalog.warning("Cannot get item.")
pass
# Append module to fit
moduleList.append(m)
@@ -797,6 +810,7 @@ class Port(object):
wx.CallAfter(callback, None)
# Skip fit silently if we get an exception
except Exception:
+ pyfalog.error("Caught exception on fit.")
pass
return fits
@@ -821,6 +835,7 @@ class Port(object):
except ValueError:
f.ship = Citadel(sMkt.getItem(shipType))
except:
+ pyfalog.warning("Caught exception on importXml")
continue
hardwares = fitting.getElementsByTagName("hardware")
moduleList = []
@@ -830,6 +845,7 @@ class Port(object):
try:
item = sMkt.getItem(moduleName, eager="group.category")
except:
+ pyfalog.warning("Caught exception on importXml")
continue
if item:
if item.category.name == "Drone":
@@ -852,6 +868,7 @@ class Port(object):
m = Module(item)
# When item can't be added to any slot (unknown item or just charge), ignore it
except ValueError:
+ pyfalog.warning("item can't be added to any slot (unknown item or just charge), ignore it")
continue
# Add subsystems before modules to make sure T3 cruisers have subsystems installed
if item.category.name == "Subsystem":
@@ -865,6 +882,7 @@ class Port(object):
moduleList.append(m)
except KeyboardInterrupt:
+ pyfalog.warning("Keyboard Interrupt")
continue
# Recalc to get slot numbers correct for T3 cruisers
@@ -1171,7 +1189,7 @@ class FitImportThread(threading.Thread):
success, result = sPort.importFitFromFiles(self.paths, self.callback)
if not success: # there was an error during processing
- logger.error("Error while processing file import: %s", result)
+ pyfalog.error("Error while processing file import: {0}", result)
wx.CallAfter(self.callback, -2, result)
else: # Send done signal to GUI
wx.CallAfter(self.callback, -1, result)
diff --git a/service/prefetch.py b/service/prefetch.py
index 06e6894c2..e73da9ff5 100644
--- a/service/prefetch.py
+++ b/service/prefetch.py
@@ -25,9 +25,9 @@ from eos.db import migration
from eos.db.saveddata.loadDefaultDatabaseValues import DefaultDatabaseValues
from eos.db.saveddata.databaseRepair import DatabaseCleanup
-import logging
+from logbook import Logger
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
# Make sure the saveddata db exists
if config.savePath and not os.path.exists(config.savePath):
@@ -35,14 +35,16 @@ if config.savePath and not os.path.exists(config.savePath):
if config.saveDB and os.path.isfile(config.saveDB):
# If database exists, run migration after init'd database
+ pyfalog.debug("Run database migration.")
db.saveddata_meta.create_all()
migration.update(db.saveddata_engine)
# Import default database values
# Import values that must exist otherwise Pyfa breaks
+ pyfalog.debug("Import Required Database Values.")
DefaultDatabaseValues.importRequiredDefaults()
# Finds and fixes database corruption issues.
- logging.debug("Starting database validation.")
+ pyfalog.debug("Starting database validation.")
database_cleanup_instance = DatabaseCleanup()
database_cleanup_instance.OrphanedCharacterSkills(db.saveddata_engine)
database_cleanup_instance.OrphanedFitCharacterIDs(db.saveddata_engine)
@@ -52,7 +54,7 @@ if config.saveDB and os.path.isfile(config.saveDB):
database_cleanup_instance.OrphanedFitIDItemID(db.saveddata_engine)
database_cleanup_instance.NullDamageTargetPatternValues(db.saveddata_engine)
database_cleanup_instance.DuplicateSelectedAmmoName(db.saveddata_engine)
- logging.debug("Completed database validation.")
+ pyfalog.debug("Completed database validation.")
else:
# If database does not exist, do not worry about migration. Simply
diff --git a/service/price.py b/service/price.py
index 32e2f20bd..ca2db812f 100644
--- a/service/price.py
+++ b/service/price.py
@@ -23,6 +23,8 @@ from xml.dom import minidom
from eos import db
from service.network import Network, TimeoutError
+from logbook import Logger
+pyfalog = Logger(__name__)
VALIDITY = 24 * 60 * 60 # Price validity period, 24 hours
REREQUEST = 4 * 60 * 60 # Re-request delay for failed fetches, 4 hours
@@ -114,6 +116,7 @@ class Price(object):
# If getting or processing data returned any errors
except TimeoutError:
# Timeout error deserves special treatment
+ pyfalog.warning("Price fetch timout")
for typeID in priceMap.keys():
priceobj = priceMap[typeID]
priceobj.time = time.time() + TIMEOUT
@@ -121,6 +124,7 @@ class Price(object):
del priceMap[typeID]
except:
# all other errors will pass and continue onward to the REREQUEST delay
+ pyfalog.warning("Caught exception in fetchPrices")
pass
# if we get to this point, then we've got an error. Set to REREQUEST delay
diff --git a/service/pycrest/__init__.py b/service/pycrest/__init__.py
index f083e1f84..5820a7290 100644
--- a/service/pycrest/__init__.py
+++ b/service/pycrest/__init__.py
@@ -1,12 +1 @@
-import logging
-
-
-class NullHandler(logging.Handler):
- def emit(self, record):
- pass
-
-
-logger = logging.getLogger('pycrest')
-logger.addHandler(NullHandler())
-
version = "0.0.1"
diff --git a/service/pycrest/eve.py b/service/pycrest/eve.py
index c96a10885..14e9d531c 100644
--- a/service/pycrest/eve.py
+++ b/service/pycrest/eve.py
@@ -1,5 +1,5 @@
import base64
-import logging
+from logbook import Logger
import os
import re
import time
@@ -20,7 +20,7 @@ except ImportError: # pragma: no cover
# noinspection PyPep8Naming
import cPickle as pickle
-logger = logging.getLogger("pycrest.eve")
+pyfalog = Logger(__name__)
cache_re = re.compile(r'max-age=([0-9]+)')
@@ -58,6 +58,7 @@ class FileCache(APICache):
with open(self._getpath(key), 'rb') as f:
return pickle.loads(zlib.decompress(f.read()))
except IOError as ex:
+ pyfalog.debug("IO error opening zip file. (May not exist yet)")
if ex.errno == 2: # file does not exist (yet)
return None
else:
@@ -69,6 +70,8 @@ class FileCache(APICache):
try:
os.unlink(self._getpath(key))
except OSError as ex:
+ pyfalog.debug("Caught exception in invalidate")
+ pyfalog.debug(ex)
if ex.errno == 2: # does not exist
pass
else:
@@ -116,7 +119,7 @@ class APIConnection(object):
self.cache = DictCache()
def get(self, resource, params=None):
- logger.debug('Getting resource %s', resource)
+ pyfalog.debug('Getting resource %s', resource)
if params is None:
params = {}
@@ -136,15 +139,15 @@ class APIConnection(object):
key = (resource, frozenset(self._session.headers.items()), frozenset(prms.items()))
cached = self.cache.get(key)
if cached and cached['cached_until'] > time.time():
- logger.debug('Cache hit for resource %s (params=%s)', resource, prms)
+ pyfalog.debug('Cache hit for resource %s (params=%s)', resource, prms)
return cached
elif cached:
- logger.debug('Cache stale for resource %s (params=%s)', resource, prms)
+ pyfalog.debug('Cache stale for resource %s (params=%s)', resource, prms)
self.cache.invalidate(key)
else:
- logger.debug('Cache miss for resource %s (params=%s', resource, prms)
+ pyfalog.debug('Cache miss for resource %s (params=%s', resource, prms)
- logger.debug('Getting resource %s (params=%s)', resource, prms)
+ pyfalog.debug('Getting resource %s (params=%s)', resource, prms)
res = self._session.get(resource, params=prms)
if res.status_code != 200:
raise APIException("Got unexpected status code from server: %i" % res.status_code)
diff --git a/service/server.py b/service/server.py
index 9fc93f05f..c804db439 100644
--- a/service/server.py
+++ b/service/server.py
@@ -2,14 +2,13 @@ import BaseHTTPServer
import urlparse
import socket
import thread
-import logging
+from logbook import Logger
# noinspection PyPackageRequirements
import wx
from service.settings import CRESTSettings
-
-logger = logging.getLogger(__name__)
+pyfalog = Logger(__name__)
# noinspection PyPep8
HTML = '''
@@ -85,7 +84,7 @@ class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
# Allow listening for x seconds
sec = self.settings.get('timeout')
- logger.debug("Running server for %d seconds", sec)
+ pyfalog.debug("Running server for {0} seconds", sec)
self.socket.settimeout(0.5)
self.max_tries = sec / self.socket.gettimeout()
@@ -99,16 +98,17 @@ class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
sock.settimeout(None)
return sock, addr
except socket.timeout:
+ pyfalog.warning("Server timed out waiting for connection")
pass
def stop(self):
self.run = False
def handle_timeout(self):
- # logger.debug("Number of tries: %d"%self.tries)
+ # pyfalog.debug("Number of tries: %d"%self.tries)
self.tries += 1
if self.tries == self.max_tries:
- logger.debug("Server timed out waiting for connection")
+ pyfalog.debug("Server timed out waiting for connection")
self.stop()
def serve(self, callback):
@@ -117,6 +117,7 @@ class StoppableHTTPServer(BaseHTTPServer.HTTPServer):
try:
self.handle_request()
except TypeError:
+ pyfalog.debug("Caught exception in serve")
pass
self.server_close()
diff --git a/service/update.py b/service/update.py
index 969c78432..2cffd9cec 100644
--- a/service/update.py
+++ b/service/update.py
@@ -29,6 +29,9 @@ import dateutil.parser
import config
from service.network import Network
from service.settings import UpdateSettings
+from logbook import Logger
+
+pyfalog = Logger(__name__)
class CheckUpdateThread(threading.Thread):
@@ -83,6 +86,7 @@ class CheckUpdateThread(threading.Thread):
wx.CallAfter(self.callback, release) # Singularity -> Singularity
break
except:
+ pyfalog.warning("Caught exception in run")
pass
@staticmethod