1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-06-17 07:41:13 +03:00

Merge pull request #719 from EDCD/enhancement/trace-logging

Implement a TRACE level of logging
This commit is contained in:
Athanasius 2020-09-28 11:19:24 +01:00 committed by GitHub
commit ae82f27925
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 287 additions and 81 deletions

4
.mypy.ini Normal file
View File

@ -0,0 +1,4 @@
[mypy]
follow_imports = skip
ignore_missing_imports = True
scripts_are_modules = True

67
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,67 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
hooks:
- id: check-merge-conflict
- id: debug-statements
- id: end-of-file-fixer
- id: mixed-line-ending
#- repo: https://github.com/pre-commit/mirrors-autopep8
# rev: ''
# hooks:
# - id: autopep8
# flake8 --show-source <file>
- repo: https://gitlab.com/pycqa/flake8
rev: ''
hooks:
- id: flake8
- repo: https://github.com/pre-commit/pygrep-hooks
rev: ''
hooks:
- id: python-no-eval
- id: python-no-log-warn
# This is a pain where a comment begins with the word 'type' otherwise
# - id: python-use-type-annotations
# mypy - static type checking
# mypy --follow-imports skip <file>
- repo: https://github.com/pre-commit/mirrors-mypy
rev: ''
hooks:
- id: mypy
args: [ "--follow-imports", "skip", "--ignore-missing-imports", "--scripts-are-modules" ]
### # pydocstyle.exe <file>
### - repo: https://github.com/FalconSocial/pre-commit-mirrors-pep257
### rev: ''
### hooks:
### - id: pep257 # docstring conventions
### # Alternate https://github.com/PyCQA/pydocstyle
# - repo: https://github.com/digitalpulp/pre-commit-php
# rev: ''
# hooks:
# -id: php-unit
# safety.exe check -r requirements.txt
- repo: https://github.com/Lucas-C/pre-commit-hooks-safety
rev: ''
hooks:
- id: python-safety-dependencies-check
entry: safety
args: [check, --bare, -r]
language: system
default_language_version:
python: python3.7
default_stages: [ commit, push ]
#files: '([^\.].+/)*.py'
exclude: cp37-setup-new.py

70
EDMC.py
View File

@ -1,19 +1,24 @@
#!/usr/bin/env python3
#
# Command-line interface. Requires prior setup through the GUI.
#
"""Command-line interface. Requires prior setup through the GUI."""
import argparse
import json
import locale
import logging
import os
import re
import sys
from os.path import getmtime, join
from time import sleep, time
from typing import Any, Optional
from typing import TYPE_CHECKING, Any, Optional
# See EDMCLogging.py docs.
# isort: off
from EDMCLogging import edmclogger, logger, logging
if TYPE_CHECKING:
from logging import trace, TRACE # type: ignore # noqa: F401
# isort: on
edmclogger.set_channels_loglevel(logging.INFO)
# workaround for https://github.com/EDCD/EDMarketConnector/issues/568
os.environ["EDMC_NO_UI"] = "1"
@ -21,7 +26,6 @@ os.environ["EDMC_NO_UI"] = "1"
import collate
import commodity
import companion
import EDMCLogging
import edshipyard
import l10n
import loadout
@ -40,11 +44,9 @@ sys.path.append(config.internal_plugin_dir)
import eddn # noqa: E402
# isort: on
logger = EDMCLogging.Logger(appcmdname).get_logger()
logger.setLevel(logging.INFO)
def log_locale(prefix: str) -> None:
"""Log the current state of locale settings."""
logger.debug(f'''Locale: {prefix}
Locale LC_COLLATE: {locale.getlocale(locale.LC_COLLATE)}
Locale LC_CTYPE: {locale.getlocale(locale.LC_CTYPE)}
@ -62,12 +64,30 @@ EXIT_SUCCESS, EXIT_SERVER, EXIT_CREDENTIALS, EXIT_VERIFICATION, EXIT_LAGGING, EX
JOURNAL_RE = re.compile(r'^Journal(Beta)?\.[0-9]{12}\.[0-9]{2}\.log$')
# quick and dirty version comparison assuming "strict" numeric only version numbers
def versioncmp(versionstring):
"""Quick and dirty version comparison assuming "strict" numeric only version numbers."""
return list(map(int, versionstring.split('.')))
def deep_get(target: dict, *args: str, default=None) -> Any:
"""
Walk into a dict and return the specified deep value.
Example usage:
>>> thing = {'a': {'b': {'c': 'foo'} } }
>>> deep_get(thing, ('a', 'b', 'c'), None)
'foo'
>>> deep_get(thing, ('a', 'b'), None)
{'c': 'foo'}
>>> deep_get(thing, ('a', 'd'), None)
None
:param target: The dict to walk into for the desired value.
:param args: The list of keys to walk down through.
:param default: What to return if the target has no value.
:return: The value at the target deep key.
"""
if not hasattr(target, 'get'):
raise ValueError(f"Cannot call get on {target} ({type(target)})")
@ -83,6 +103,7 @@ def deep_get(target: dict, *args: str, default=None) -> Any:
def main():
"""Run the main code of the program."""
try:
# arg parsing
parser = argparse.ArgumentParser(
@ -93,7 +114,16 @@ def main():
)
parser.add_argument('-v', '--version', help='print program version and exit', action='store_const', const=True)
parser.add_argument('--loglevel', metavar='loglevel', help='Set the logging loglevel to one of: CRITICAL, ERROR, WARNING, INFO, DEBUG') # noqa: E501
group_loglevel = parser.add_mutually_exclusive_group()
group_loglevel.add_argument('--loglevel',
metavar='loglevel',
help='Set the logging loglevel to one of: '
'CRITICAL, ERROR, WARNING, INFO, DEBUG, TRACE',
)
group_loglevel.add_argument('--trace',
help='Set the Debug logging loglevel to TRACE',
action='store_true',
)
parser.add_argument('-a', metavar='FILE', help='write ship loadout to FILE in Companion API json format')
parser.add_argument('-e', metavar='FILE', help='write ship loadout to FILE in E:D Shipyard plain text format')
parser.add_argument('-l', metavar='FILE', help='write ship locations to FILE in CSV format')
@ -117,11 +147,14 @@ def main():
return
if args.loglevel:
if args.loglevel not in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'):
print('loglevel must be one of: CRITICAL, ERROR, WARNING, INFO, DEBUG', file=sys.stderr)
if args.trace:
edmclogger.set_channels_loglevel(logging.TRACE)
elif args.loglevel:
if args.loglevel not in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'TRACE'):
print('loglevel must be one of: CRITICAL, ERROR, WARNING, INFO, DEBUG, TRACE', file=sys.stderr)
sys.exit(EXIT_ARGS)
logger.setLevel(args.loglevel)
edmclogger.set_channels_loglevel(args.loglevel)
logger.debug(f'Startup v{appversion} : Running on Python v{sys.version}')
logger.debug(f'''Platform: {sys.platform}
@ -250,10 +283,9 @@ sys.path: {sys.path}'''
stats.export_status(data, args.t)
if data['commander'].get('docked'):
print('{},{}'.format(
deep_get(data, 'lastSystem', 'name', default='Unknown'),
deep_get(data, 'lastStarport', 'name', default='Unknown')
))
print(f'{deep_get(data, "lastSystem", "name", default="Unknown")},'
f'{deep_get(data, "lastStarport", "name", default="Unknown")}'
)
else:
print(deep_get(data, 'lastSystem', 'name', default='Unknown'))

View File

@ -5,6 +5,34 @@ This module provides for a common logging-powered log facility.
Mostly it implements a logging.Filter() in order to get two extra
members on the logging.LogRecord instance for use in logging.Formatter()
strings.
If type checking, e.g. mypy, objects to `logging.trace(...)` then include this
stanza:
# See EDMCLogging.py docs.
# isort: off
if TYPE_CHECKING:
from logging import trace, TRACE # type: ignore # noqa: F401
# isort: on
This is needed because we add the TRACE level and the trace() function
ourselves at runtime.
To utilise logging in core code, or internal plugins, include this:
from EDMCLogging import get_main_logger
logger = get_main_logger()
To utilise logging in a 'found' (third-party) plugin, include this:
import os
import logging
plugin_name = os.path.basename(os.path.dirname(__file__))
# plugin_name here *must* be the name of the folder the plugin resides in
# See, plug.py:load_plugins()
logger = logging.getLogger(f'{appname}.{plugin_name}')
"""
import inspect
@ -44,6 +72,17 @@ from config import appcmdname, appname, config
_default_loglevel = logging.DEBUG
# Define a TRACE level
LEVEL_TRACE = 5
logging.addLevelName(LEVEL_TRACE, "TRACE")
logging.TRACE = LEVEL_TRACE # type: ignore
logging.Logger.trace = lambda self, message, *args, **kwargs: self._log( # type: ignore
logging.TRACE, # type: ignore
message,
args,
**kwargs
)
class Logger:
"""
@ -66,9 +105,9 @@ class Logger:
"""
self.logger = logging.getLogger(logger_name)
# Configure the logging.Logger
# This needs to always be DEBUG in order to let DEBUG level messages
# This needs to always be TRACE in order to let TRACE level messages
# through to check the *handler* levels.
self.logger.setLevel(logging.DEBUG)
self.logger.setLevel(logging.TRACE) # type: ignore
# Set up filter for adding class name
self.logger_filter = EDMCContextFilter()
@ -102,8 +141,8 @@ class Logger:
encoding='utf-8',
delay=False
)
# Yes, we always want these rotated files to be at DEBUG level
self.logger_channel_rotating.setLevel(logging.DEBUG)
# Yes, we always want these rotated files to be at TRACE level
self.logger_channel_rotating.setLevel(logging.TRACE) # type: ignore
self.logger_channel_rotating.setFormatter(self.logger_formatter)
self.logger.addHandler(self.logger_channel_rotating)
@ -118,10 +157,33 @@ class Logger:
def get_streamhandler(self) -> logging.Handler:
"""
Obtain the self.logger_channel StreamHandler instance.
:return: logging.StreamHandler
"""
return self.logger_channel
def set_channels_loglevel(self, level: int) -> None:
"""
Set the specified log level on the channels.
:param level: A valid `logging` level.
:return: None
"""
self.logger_channel.setLevel(level)
self.logger_channel_rotating.setLevel(level)
def set_console_loglevel(self, level: int) -> None:
"""
Set the specified log level on the console channel.
:param level: A valid `logging` level.
:return: None
"""
if self.logger_channel.level != logging.TRACE: # type: ignore
self.logger_channel.setLevel(level)
else:
logger.trace("Not changing log level because it's TRACE") # type: ignore
def get_plugin_logger(plugin_name: str, loglevel: int = _default_loglevel) -> logging.Logger:
"""
@ -131,16 +193,21 @@ def get_plugin_logger(plugin_name: str, loglevel: int = _default_loglevel) -> lo
coming from, but we don't need to set up *everything* for them.
The name will be '{config.appname}.{plugin.name}', e.g.
'EDMarketConnector.miggytest'. This means that any logging sent through
there *also* goes to the channels defined in the 'EDMarketConnector'
logger, so we can let that take care of the formatting.
'EDMarketConnector.plugintest', or using appcmdname for EDMC CLI tool.
Note that `plugin_name` must be the same as the name of the folder the
plugin resides in.
This means that any logging sent through there *also* goes to the channels
defined in the 'EDMarketConnector' (or 'EDMC') logger, so we can let that
take care of the formatting.
If we add our own channel then the output gets duplicated (assuming same
logLevel set).
However we do need to attach our filter to this still. That's not at
the channel level.
:param name: Name of this Logger.
:param plugin_name: Name of this Logger. **Must** be the name of the
folder the plugin resides in.
:param loglevel: Optional logLevel for this Logger.
:return: logging.Logger instance, all set up.
"""
@ -335,7 +402,6 @@ class EDMCContextFilter(logging.Filter):
def get_main_logger() -> logging.Logger:
"""Return the correct logger for how the program is being run."""
if not os.getenv("EDMC_NO_UI"):
# GUI app being run
return logging.getLogger(appname)
@ -348,5 +414,11 @@ def get_main_logger() -> logging.Logger:
loglevel = config.get('loglevel')
if not loglevel:
loglevel = logging.INFO
edmclogger = Logger(appname, loglevel=loglevel)
if not os.getenv('EDMC_NO_UI'):
base_logger_name = appname
else:
base_logger_name = appcmdname
edmclogger = Logger(base_logger_name, loglevel=loglevel)
logger = edmclogger.get_logger()

View File

@ -0,0 +1 @@
EDMarketConnector.exe --trace

View File

@ -1,20 +1,29 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from builtins import str
from builtins import object
import sys
from sys import platform
import argparse
import html
import json
import locale
import re
import sys
import webbrowser
from builtins import object, str
from os import chdir, environ
from os.path import dirname, isdir, join
import re
import html
from time import time, localtime, strftime
import webbrowser
from sys import platform
from time import localtime, strftime, time
from typing import TYPE_CHECKING
from config import appname, applongname, appversion, appversion_nobuild, copyright, config
from EDMCLogging import edmclogger, logger, logging
# See EDMCLogging.py docs.
# isort: off
if TYPE_CHECKING:
from logging import trace, TRACE # type: ignore # noqa: F401
# isort: on
from config import applongname, appname, appversion, appversion_nobuild, config, copyright
# TODO: Test: Make *sure* this redirect is working, else py2exe is going to cause an exit popup
if __name__ == "__main__":
@ -36,10 +45,11 @@ if getattr(sys, 'frozen', False):
environ['TK_LIBRARY'] = join(dirname(sys.path[0]), 'lib', 'tk')
import tkinter as tk
from tkinter import ttk
import tkinter.filedialog
import tkinter.font
import tkinter.messagebox
from tkinter import ttk
from ttkHyperlinkLabel import HyperlinkLabel
if __debug__:
@ -49,18 +59,18 @@ if __debug__:
signal.signal(signal.SIGTERM, lambda sig, frame: pdb.Pdb().set_trace(frame))
import companion
import commodity
from commodity import COMMODITY_CSV
import td
import stats
import prefs
import companion
import plug
import prefs
import stats
import td
from commodity import COMMODITY_CSV
from dashboard import dashboard
from hotkey import hotkeymgr
from l10n import Translations
from monitor import monitor
from protocol import protocolhandler
from dashboard import dashboard
from theme import theme
SERVER_RETRY = 5 # retry pause for Companion servers [s]
@ -613,17 +623,17 @@ class AppWindow(object):
def crewroletext(role):
# Return translated crew role. Needs to be dynamic to allow for changing language.
return {
None : '',
'Idle' : '',
None: '',
'Idle': '',
'FighterCon': _('Fighter'), # Multicrew role
'FireCon' : _('Gunner'), # Multicrew role
'FlightCon' : _('Helm'), # Multicrew role
'FireCon': _('Gunner'), # Multicrew role
'FlightCon': _('Helm'), # Multicrew role
}.get(role, role)
while True:
entry = monitor.get_entry()
if not entry:
logger.debug('No entry from monitor.get_entry()')
logger.trace('No entry from monitor.get_entry()')
return
# Update main window
@ -640,8 +650,8 @@ class AppWindow(object):
self.ship_label['text'] = _('Ship') + ':' # Main window
self.ship.configure(
text=monitor.state['ShipName']
or companion.ship_map.get(monitor.state['ShipType'], monitor.state['ShipType'])
or '',
or companion.ship_map.get(monitor.state['ShipType'], monitor.state['ShipType'])
or '',
url=self.shipyard_url)
else:
self.cmdr['text'] = ''
@ -675,7 +685,7 @@ class AppWindow(object):
self.login()
if not entry['event'] or not monitor.mode:
logger.debug('Startup or in CQC, returning')
logger.trace('Startup or in CQC, returning')
return # Startup or in CQC
if entry['event'] in ['StartUp', 'LoadGame'] and monitor.started:
@ -934,7 +944,8 @@ class AppWindow(object):
def onexit(self, event=None):
# http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7
if platform != 'darwin' or self.w.winfo_rooty() > 0:
config.set('geometry', '+{1}+{2}'.format(*self.w.geometry().split('+')))
x, y = self.w.geometry().split('+')[1:3] # e.g. '212x170+2881+1267'
config.set('geometry', f'+{x}+{y}')
self.w.withdraw() # Following items can take a few seconds, so hide the main window while they happen
protocolhandler.close()
hotkeymgr.unregister()
@ -986,13 +997,13 @@ def enforce_single_instance() -> None:
# Ensure only one copy of the app is running under this user account. OSX does this automatically. Linux TODO.
if platform == 'win32':
import ctypes
from ctypes.wintypes import HWND, LPWSTR, LPCWSTR, INT, BOOL, LPARAM
from ctypes.wintypes import BOOL, HWND, INT, LPARAM, LPCWSTR, LPWSTR
EnumWindows = ctypes.windll.user32.EnumWindows # noqa: N806
GetClassName = ctypes.windll.user32.GetClassNameW # noqa: N806
GetClassName.argtypes = [HWND, LPWSTR, ctypes.c_int] # noqa: N806
GetClassName.argtypes = [HWND, LPWSTR, ctypes.c_int]
GetWindowText = ctypes.windll.user32.GetWindowTextW # noqa: N806
GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int] # noqa: N806
GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int]
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW # noqa: N806
GetProcessHandleFromHwnd = ctypes.windll.oleacc.GetProcessHandleFromHwnd # noqa: N806
@ -1059,7 +1070,27 @@ Locale LC_TIME: {locale.getlocale(locale.LC_TIME)}'''
if __name__ == "__main__":
enforce_single_instance()
from EDMCLogging import logger
# Command-line arguments
parser = argparse.ArgumentParser(
prog=appname,
description="Utilises Elite Dangerous Journal files and the Frontier "
"Companion API (CAPI) service to gather data about a "
"player's state and actions to upload to third-party sites "
"such as EDSM, Inara.cz and EDDB."
)
parser.add_argument('--trace',
help='Set the Debug logging loglevel to TRACE',
action='store_true',
)
args = parser.parse_args()
if args.trace:
logger.setLevel(logging.TRACE)
edmclogger.set_channels_loglevel(logging.TRACE)
else:
edmclogger.set_channels_loglevel(logging.DEBUG)
logger.info(f'Startup v{appversion} : Running on Python v{sys.version}')
logger.debug(f'''Platform: {sys.platform}
@ -1114,7 +1145,7 @@ sys.path: {sys.path}'''
ui_scale = 100
config.set('ui_scale', ui_scale)
theme.default_ui_scale = root.tk.call('tk', 'scaling')
logger.debug(f'Default tk scaling = {theme.default_ui_scale}')
logger.trace(f'Default tk scaling = {theme.default_ui_scale}')
theme.startup_ui_scale = ui_scale
root.tk.call('tk', 'scaling', theme.default_ui_scale * float(ui_scale) / 100.0)
app = AppWindow(root)

View File

@ -274,7 +274,7 @@ class Auth(object):
s = random.SystemRandom().getrandbits(8 * 32)
self.state = self.base64_url_encode(s.to_bytes(32, byteorder='big'))
# Won't work under IE: https://blogs.msdn.microsoft.com/ieinternals/2011/07/13/understanding-protocols/
logger.debug(f'Trying auth from scratch for Commander "{self.cmdr}"')
logger.info(f'Trying auth from scratch for Commander "{self.cmdr}"')
challenge = self.base64_url_encode(hashlib.sha256(self.verifier).digest())
webbrowser.open(
f'{SERVER_AUTH}{URL_AUTH}?response_type=code&audience=frontier&scope=capi&client_id={CLIENT_ID}&code_challenge={challenge}&code_challenge_method=S256&state={self.state}&redirect_uri={protocolhandler.redirect}' # noqa: E501 # I cant make this any shorter
@ -399,7 +399,7 @@ class Session(object):
raise CredentialsError('Missing credentials') # Shouldn't happen
elif self.state == Session.STATE_OK:
logger.debug('already logged in')
logger.debug('already logged in (state == STATE_OK)')
return True # already logged in
else:
@ -409,7 +409,6 @@ class Session(object):
return True # already logged in
else:
# changed account or retrying login during auth
logger.debug('changed account or retrying login during auth')
self.close()
self.credentials = credentials
@ -461,7 +460,7 @@ class Session(object):
def query(self, endpoint: str) -> CAPIData:
"""Perform a query against the specified CAPI endpoint."""
logger.debug(f'Performing query for endpoint "{endpoint}"')
logger.trace(f'Performing query for endpoint "{endpoint}"')
if self.state == Session.STATE_INIT:
if self.login():
return self.query(endpoint)
@ -471,7 +470,7 @@ class Session(object):
raise CredentialsError('cannot make a query when unauthorized')
try:
logger.debug('Trying...')
logger.trace('Trying...')
r = self.session.get(self.server + endpoint, timeout=timeout)
except Exception as e:
@ -479,7 +478,7 @@ class Session(object):
raise ServerError(f'unable to get endpoint {endpoint}') from e
if r.url.startswith(SERVER_AUTH):
logger.debug('Redirected back to Auth Server')
logger.info('Redirected back to Auth Server')
# Redirected back to Auth server - force full re-authentication
self.dump(r)
self.invalidate()
@ -521,7 +520,7 @@ class Session(object):
self.retrying = False
if 'timestamp' not in data:
logger.debug('timestamp not in data, adding from response headers')
logger.trace('timestamp not in data, adding from response headers')
data['timestamp'] = time.strftime('%Y-%m-%dT%H:%M:%SZ', parsedate(r.headers['Date'])) # type: ignore
return data

View File

@ -243,7 +243,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
for line in loghandle:
try:
if b'"event":"Location"' in line:
logger.debug('"Location" event in the past at startup')
logger.trace('"Location" event in the past at startup')
self.parse_entry(line) # Some events are of interest even in the past
@ -327,7 +327,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
loghandle.seek(log_pos, SEEK_SET) # reset EOF flag # TODO: log_pos reported as possibly unbound
for line in loghandle:
if b'"event":"Location"' in line:
logger.debug('Found "Location" event, appending to event_queue')
logger.trace('Found "Location" event, appending to event_queue')
self.event_queue.append(line)
@ -340,7 +340,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
# Check whether we're still supposed to be running
if threading.current_thread() != self.thread:
logger.inof("We're not meant to be running, exiting...")
logger.info("We're not meant to be running, exiting...")
return # Terminate
if self.game_was_running:
@ -538,7 +538,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
self.planet = entry.get('Body') if entry.get('BodyType') == 'Planet' else None
if event_type == 'Location':
logger.debug('"Location" event')
logger.trace('"Location" event')
elif event_type == 'FSDJump':
self.planet = None
@ -827,7 +827,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
entry = self.parse_entry(self.event_queue.pop(0))
if entry['event'] == 'Location':
logger.debug('"Location" event')
logger.trace('"Location" event')
if not self.live and entry['event'] not in (None, 'Fileheader'):
# Game not running locally, but Journal has been updated
@ -856,7 +856,7 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
])
if entry['event'] == 'Location':
logger.debug('Appending "Location" event to event_queue')
logger.trace('Appending "Location" event to event_queue')
self.event_queue.append(json.dumps(entry, separators=(', ', ':')))

View File

@ -304,7 +304,7 @@ def notify_journal_entry(cmdr, is_beta, system, station, entry, state):
:returns: Error message from the first plugin that returns one (if any)
"""
if entry['event'] in ('Location'):
logger.debug('Notifying plugins of "Location" event')
logger.trace('Notifying plugins of "Location" event')
error = None
for plugin in PLUGINS:

View File

@ -333,7 +333,7 @@ def journal_entry(
) -> None:
"""Journal Entry hook."""
if entry['event'] in ('CarrierJump', 'FSDJump', 'Location', 'Docked'):
logger.debug(f'''{entry["event"]}
logger.trace(f'''{entry["event"]}
Commander: {cmdr}
System: {system}
Station: {station}
@ -431,7 +431,7 @@ entry: {entry!r}'''
this.queue.put((cmdr, materials))
if entry['event'] in ('CarrierJump', 'FSDJump', 'Location', 'Docked'):
logger.debug(f'''{entry["event"]}
logger.trace(f'''{entry["event"]}
Queueing: {entry!r}'''
)
this.queue.put((cmdr, entry))
@ -530,12 +530,12 @@ def worker() -> None:
if should_send(pending):
if any(p for p in pending if p['event'] in ('CarrierJump', 'FSDJump', 'Location', 'Docked')):
logger.debug("pending has at least one of "
logger.trace("pending has at least one of "
"('CarrierJump', 'FSDJump', 'Location', 'Docked')"
" and it passed should_send()")
for p in pending:
if p['event'] in ('Location'):
logger.debug('"Location" event in pending passed should_send(), '
logger.trace('"Location" event in pending passed should_send(), '
f'timestamp: {p["timestamp"]}')
creds = credentials(cmdr) # TODO: possibly unbound
@ -554,13 +554,13 @@ def worker() -> None:
if any(p for p in pending if p['event'] in ('CarrierJump', 'FSDJump', 'Location', 'Docked')):
data_elided = data.copy()
data_elided['apiKey'] = '<elided>'
logger.debug("pending has at least one of "
logger.trace("pending has at least one of "
"('CarrierJump', 'FSDJump', 'Location', 'Docked')"
" Attempting API cal...")
for p in pending:
if p['event'] in ('Location'):
logger.debug('Attempting API call for "Location" event with timestamp: '
logger.trace('Attempting API call for "Location" event with timestamp: '
f'{p["timestamp"]}')
r = this.session.post('https://www.edsm.net/api-journal-v1', data=data, timeout=_TIMEOUT)

View File

@ -14,7 +14,7 @@ from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union
import myNotebook as nb # noqa: N813
import plug
from config import applongname, appname, appversion, config
from config import applongname, appversion, config
from EDMCLogging import edmclogger, get_main_logger
from hotkey import hotkeymgr
from l10n import Translations
@ -1060,7 +1060,7 @@ class PreferencesDialog(tk.Toplevel):
config.set('system_provider', self.system_provider.get())
config.set('station_provider', self.station_provider.get())
config.set('loglevel', self.select_loglevel.get())
edmclogger.get_streamhandler().setLevel(self.select_loglevel.get())
edmclogger.set_console_loglevel(self.select_loglevel.get())
lang_codes = {v: k for k, v in self.languages.items()} # Codes by name
config.set('language', lang_codes.get(self.lang.get()) or '') # or '' used here due to Default being None above