Hide registering/unregistering observers and Sentry init inside utilities/logging

Also add a check that Sentry SDK is only initialized once
pull/1124/head
Bogdan Opanchuk 2019-07-17 20:50:11 -07:00 committed by Kieran Prasch
parent 9bca91d97d
commit b473c0f4bd
No known key found for this signature in database
GPG Key ID: 199AB839D4125A62
8 changed files with 103 additions and 86 deletions

View File

@ -3,13 +3,12 @@ import sys
import datetime
import maya
from twisted.logger import globalLogPublisher
from umbral.keys import UmbralPublicKey
from nucypher.characters.lawful import Alice, Bob, Ursula
from nucypher.characters.lawful import Enrico as Enrico
from nucypher.network.middleware import RestMiddleware
from nucypher.utilities.logging import SimpleObserver, GlobalConsoleLogger
from nucypher.utilities.logging import GlobalLoggerSettings
from nucypher.utilities.sandbox.constants import TEMPORARY_DOMAIN
######################
@ -24,8 +23,8 @@ BOOK_PATH = os.path.join('.', 'finnegans-wake.txt')
NUMBER_OF_LINES_TO_REENCRYPT = 25
# Twisted Logger
globalLogPublisher.addObserver(SimpleObserver())
GlobalConsoleLogger.set_log_level(log_level_name='debug')
GlobalLoggerSettings.set_log_level(log_level_name='debug')
GlobalLoggerSettings.start_console_logging()
#######################################

View File

@ -5,11 +5,10 @@ import os
import shutil
import maya
from twisted.logger import globalLogPublisher
from nucypher.characters.lawful import Bob, Ursula
from nucypher.config.characters import AliceConfiguration
from nucypher.utilities.logging import SimpleObserver
from nucypher.utilities.logging import GlobalLoggerSettings
######################
@ -20,7 +19,7 @@ from nucypher.utilities.logging import SimpleObserver
# Twisted Logger
from nucypher.utilities.sandbox.constants import TEMPORARY_DOMAIN
globalLogPublisher.addObserver(SimpleObserver())
GlobalLoggerSettings.start_console_logging()
TEMP_ALICE_DIR = os.path.join('/', 'tmp', 'heartbeat-demo-alice')

View File

@ -7,8 +7,6 @@ import maya
import traceback
from timeit import default_timer as timer
from twisted.logger import globalLogPublisher
from nucypher.characters.lawful import Bob, Ursula, Enrico
from nucypher.crypto.kits import UmbralMessageKit
from nucypher.crypto.powers import DecryptingPower, SigningPower
@ -17,10 +15,11 @@ from nucypher.network.middleware import RestMiddleware
from umbral.keys import UmbralPublicKey
from nucypher.utilities.logging import SimpleObserver
from nucypher.utilities.logging import GlobalLoggerSettings
from nucypher.utilities.sandbox.constants import TEMPORARY_DOMAIN
globalLogPublisher.addObserver(SimpleObserver())
GlobalLoggerSettings.start_console_logging()
######################
# Boring setup stuff #

View File

@ -20,15 +20,10 @@ import os
import click
from twisted.logger import Logger
from twisted.logger import globalLogPublisher
from nucypher.config.constants import NUCYPHER_SENTRY_ENDPOINT
from nucypher.utilities.logging import (
logToSentry,
getTextFileObserver,
initialize_sentry,
getJsonFileObserver
)
from nucypher.config.node import CharacterConfiguration
from nucypher.utilities.logging import GlobalLoggerSettings
class NucypherClickConfig:
@ -48,13 +43,12 @@ class NucypherClickConfig:
# Sentry Logging
if self.log_to_sentry is True:
initialize_sentry(dsn=NUCYPHER_SENTRY_ENDPOINT)
globalLogPublisher.addObserver(logToSentry)
GlobalLoggerSettings.start_sentry_logging(self.sentry_endpoint)
# File Logging
if self.log_to_file is True:
globalLogPublisher.addObserver(getTextFileObserver())
globalLogPublisher.addObserver(getJsonFileObserver())
GlobalLoggerSettings.start_text_file_logging()
GlobalLoggerSettings.start_json_file_logging()
# You guessed it
self.debug = False

View File

@ -18,7 +18,6 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
import click
from twisted.logger import globalLogPublisher
from nucypher.characters.banners import NUCYPHER_BANNER
from nucypher.characters.control.emitters import JSONRPCStdoutEmitter
@ -28,7 +27,7 @@ from nucypher.cli.characters import moe, ursula, alice, bob, enrico, felix
from nucypher.cli.config import nucypher_click_config, NucypherClickConfig
from nucypher.cli.painting import echo_version
from nucypher.network.middleware import RestMiddleware
from nucypher.utilities.logging import GlobalConsoleLogger, getJsonFileObserver, SimpleObserver, logToSentry
from nucypher.utilities.logging import GlobalLoggerSettings
from nucypher.utilities.sandbox.middleware import MockRestMiddleware
@ -73,18 +72,18 @@ def nucypher_cli(click_config,
if debug:
click_config.log_to_sentry = False
click_config.log_to_file = True # File Logging
globalLogPublisher.addObserver(SimpleObserver()) # Console Logging
globalLogPublisher.removeObserver(logToSentry) # No Sentry
GlobalConsoleLogger.set_log_level(log_level_name='debug')
GlobalLoggerSettings.start_console_logging()
GlobalLoggerSettings.stop_sentry_logging()
GlobalLoggerSettings.set_log_level(log_level_name='debug')
elif quiet: # Disable Logging
globalLogPublisher.removeObserver(logToSentry)
globalLogPublisher.removeObserver(SimpleObserver)
globalLogPublisher.removeObserver(getJsonFileObserver())
GlobalLoggerSettings.stop_sentry_logging()
GlobalLoggerSettings.stop_console_logging()
GlobalLoggerSettings.stop_json_file_logging()
# Logging
if not no_logs:
GlobalConsoleLogger.start_if_not_started()
GlobalLoggerSettings.start_text_file_logging()
# CLI Session Configuration
click_config.verbose = verbose
@ -115,17 +114,17 @@ def nucypher_cli(click_config,
r"""
ursula
|
| moe
| /
|
| moe
| /
| /
stdin --> cli.main --- alice
| \
| \
| bob
| \
| bob
|
enrico
enrico
New character CLI modules must be added here

View File

@ -15,6 +15,7 @@ You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
from functools import lru_cache
import pathlib
from sentry_sdk import capture_exception, add_breadcrumb
@ -22,12 +23,11 @@ from sentry_sdk.integrations.logging import LoggingIntegration
from twisted.logger import FileLogObserver, jsonFileLogObserver, formatEvent, formatEventAsClassicLogText
from twisted.logger import ILogObserver
from twisted.logger import LogLevel
from twisted.logger import globalLogPublisher
from twisted.logger import globalLogPublisher, globalLogBeginner
from twisted.python.logfile import DailyLogFile
from zope.interface import provider
import nucypher
from nucypher.config.constants import USER_LOG_DIR
from nucypher.config.constants import USER_LOG_DIR, NUCYPHER_SENTRY_ENDPOINT
def initialize_sentry(dsn: str):
@ -63,8 +63,67 @@ def initialize_sentry(dsn: str):
)
def logToSentry(event):
class GlobalLoggerSettings:
log_level = LogLevel.levelWithName("info")
@classmethod
def set_log_level(cls, log_level_name):
cls.log_level = LogLevel.levelWithName(log_level_name)
@classmethod
def start_console_logging(cls):
globalLogPublisher.addObserver(console_observer)
@classmethod
def stop_console_logging(cls):
globalLogPublisher.removeObserver(console_observer)
@classmethod
def start_text_file_logging(cls):
globalLogPublisher.addObserver(get_text_file_observer())
@classmethod
def stop_text_file_logging(cls):
globalLogPublisher.removeObserver(get_text_file_observer())
@classmethod
def start_json_file_logging(cls):
globalLogPublisher.addObserver(get_json_file_observer())
@classmethod
def stop_json_file_logging(cls):
globalLogPublisher.removeObserver(get_json_file_observer())
@classmethod
def start_sentry_logging(cls, dsn: str):
_SentryInitGuard.init(dsn)
globalLogPublisher.addObserver(sentry_observer)
@classmethod
def stop_sentry_logging(cls):
globalLogPublisher.removeObserver(sentry_observer)
def console_observer(event):
if event['log_level'] >= GlobalLoggerSettings.log_level:
print(formatEvent(event))
class _SentryInitGuard:
initialized = False
dsn = None
@classmethod
def init(cls, dsn: str = NUCYPHER_SENTRY_ENDPOINT):
if not cls.initialized:
initialize_sentry(dsn)
else:
raise ValueError(f"Sentry has been already initialized with DSN {cls.dsn}")
def sentry_observer(event):
# Handle breadcrumbs...
if not event.get('isError') or 'failure' not in event:
add_breadcrumb(level=event.get('log_level').name,
@ -77,50 +136,21 @@ def logToSentry(event):
capture_exception((f.type, f.value, f.getTracebackObject()))
def _get_or_create_user_log_dir():
return pathlib.Path(USER_LOG_DIR).mkdir(parents=True, exist_ok=True)
def _ensure_dir_exists(path):
pathlib.Path(path).mkdir(parents=True, exist_ok=True)
def getJsonFileObserver(name="nucypher.log.json", path=USER_LOG_DIR): # TODO: More configurable naming here?
_get_or_create_user_log_dir()
@lru_cache()
def get_json_file_observer(name="nucypher.log.json", path=USER_LOG_DIR): # TODO: More configurable naming here?
_ensure_dir_exists(path)
logfile = DailyLogFile(name, path)
observer = jsonFileLogObserver(outFile=logfile)
return observer
def getTextFileObserver(name="nucypher.log", path=USER_LOG_DIR):
_get_or_create_user_log_dir()
@lru_cache()
def get_text_file_observer(name="nucypher.log", path=USER_LOG_DIR):
_ensure_dir_exists(path)
logfile = DailyLogFile(name, path)
observer = FileLogObserver(formatEvent=formatEventAsClassicLogText, outFile=logfile)
return observer
class SimpleObserver:
@provider(ILogObserver)
def __call__(self, event):
if event['log_level'] >= GlobalConsoleLogger.log_level:
event['log_format'] = event['log_format']
print(formatEvent(event))
class GlobalConsoleLogger:
log_level = LogLevel.levelWithName("info")
started = False
@classmethod
def set_log_level(cls, log_level_name):
cls.log_level = LogLevel.levelWithName(log_level_name)
if not cls.started:
cls.start()
@classmethod
def start(cls):
globalLogPublisher.addObserver(getTextFileObserver())
cls.started = True
@classmethod
def start_if_not_started(cls):
if not cls.started:
cls.start()

View File

@ -26,7 +26,6 @@ import os
from twisted.internet import protocol
from twisted.internet import reactor
from twisted.logger import globalLogPublisher
from nucypher.utilities.logging import SimpleObserver

View File

@ -17,21 +17,17 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
import os
import pytest
from twisted.logger import globalLogPublisher
from nucypher.characters.control.emitters import WebEmitter
from nucypher.cli.config import NucypherClickConfig
from nucypher.utilities.logging import GlobalConsoleLogger, logToSentry
from nucypher.utilities.logging import GlobalLoggerSettings
# Logger Configuration
#
from nucypher.utilities.sandbox.constants import INSECURE_DEVELOPMENT_PASSWORD
# Disable click sentry and file logging
globalLogPublisher.removeObserver(logToSentry)
NucypherClickConfig.log_to_sentry = False
# Log to files
NucypherClickConfig.log_to_file = True
# Crash on server error by default
@ -106,4 +102,6 @@ def pytest_collection_modifyitems(config, items):
log_level_name = config.getoption("--log-level", "info", skip=True)
GlobalConsoleLogger.set_log_level(log_level_name)
GlobalLoggerSettings.set_log_level(log_level_name)
GlobalLoggerSettings.start_text_file_logging()
GlobalLoggerSettings.start_json_file_logging()