1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 19:44:20 +00:00

Better colored logging

This commit is contained in:
Steffo 2019-11-24 16:02:32 +01:00
parent 075fb262cc
commit 4e16e3ee7a
11 changed files with 127 additions and 40 deletions

View file

@ -2,6 +2,5 @@
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/docs_source/royalpack" vcs="Git" />
</component> </component>
</project> </project>

View file

@ -53,10 +53,10 @@ def run(telegram: typing.Optional[bool],
royalnet_log.setLevel(log_level) royalnet_log.setLevel(log_level)
stream_handler = StreamHandler() stream_handler = StreamHandler()
if coloredlogs is not None: if coloredlogs is not None:
stream_handler.formatter = coloredlogs.ColoredFormatter("{asctime}\t| {processName}\t| {levelname}\t| {name}\t|" stream_handler.formatter = coloredlogs.ColoredFormatter("{asctime}\t| {processName}\t| {name}\t| {message}",
" {message}", style="{") style="{")
else: else:
stream_handler.formatter = Formatter("{asctime}\t| {processName}\t| {levelname}\t| {name}\t| {message}", stream_handler.formatter = Formatter("{asctime}\t| {processName}\t| {name}\t| {message}",
style="{") style="{")
royalnet_log.addHandler(stream_handler) royalnet_log.addHandler(stream_handler)
royalnet_log.debug("Logging: ready") royalnet_log.debug("Logging: ready")
@ -96,8 +96,12 @@ def run(telegram: typing.Optional[bool],
secret=get_secret("herald"), secret=get_secret("herald"),
secure=False, secure=False,
path="/") path="/")
herald_kwargs = {
"log_level": log_level
}
herald_process = multiprocessing.Process(name="Herald Server", herald_process = multiprocessing.Process(name="Herald Server",
target=r.herald.Server(config=herald_config).run_blocking, target=r.herald.Server(config=herald_config).run_blocking,
kwargs=herald_kwargs,
daemon=True) daemon=True)
herald_process.start() herald_process.start()
else: else:

View file

@ -1,10 +1,20 @@
# Imports go here! # Imports go here!
from .version import VersionCommand from .version import VersionCommand
from .exception import ExceptionCommand
from .excevent import ExceventCommand
# Enter the commands of your Pack here! # Enter the commands of your Pack here!
available_commands = [ available_commands = [
VersionCommand, VersionCommand,
] ]
# noinspection PyUnreachableCode
if __debug__:
available_commands = [
*available_commands,
ExceptionCommand,
ExceventCommand,
]
# Don't change this, it should automatically generate __all__ # Don't change this, it should automatically generate __all__
__all__ = [command.__name__ for command in available_commands] __all__ = [command.__name__ for command in available_commands]

View file

@ -0,0 +1,11 @@
import royalnet
from royalnet.commands import *
class ExceptionCommand(Command):
name: str = "exception"
description: str = "Raise an exception in the command."
async def run(self, args: CommandArgs, data: CommandData) -> None:
raise Exception(f"{self.interface.prefix}{self.name} was called")

View file

@ -0,0 +1,12 @@
import royalnet
from royalnet.commands import *
class ExceventCommand(Command):
name: str = "excevent"
description: str = "Call an event that raises an exception."
async def run(self, args: CommandArgs, data: CommandData) -> None:
await self.interface.call_herald_event(self.interface.name, "exception")
await data.reply("✅ Event called!")

View file

@ -5,10 +5,14 @@ from royalnet.commands import *
class VersionCommand(Command): class VersionCommand(Command):
name: str = "version" name: str = "version"
description: str = "Get the current Royalnet version." description: str = "Display the current Royalnet version."
async def run(self, args: CommandArgs, data: CommandData) -> None: async def run(self, args: CommandArgs, data: CommandData) -> None:
message = f" Royalnet {royalnet.__version__}\n" # noinspection PyUnreachableCode
if __debug__:
message = f" Royalnet {royalnet.__version__} (debug)\n"
else:
message = f" Royalnet {royalnet.__version__}\n"
if "69" in message: if "69" in message:
message += "(Nice.)" message += "(Nice.)"
await data.reply(message) await data.reply(message)

View file

@ -1,10 +1,14 @@
# Imports go here! # Imports go here!
from .exception import ExceptionEvent
# Enter the commands of your Pack here! # Enter the commands of your Pack here!
available_events = [ available_events = [
] ]
# noinspection PyUnreachableCode
if __debug__:
available_events.append(ExceptionEvent)
# Don't change this, it should automatically generate __all__ # Don't change this, it should automatically generate __all__
__all__ = [command.__name__ for command in available_events] __all__ = [command.__name__ for command in available_events]

View file

@ -0,0 +1,8 @@
from royalnet.commands import *
class ExceptionEvent(Event):
name = "exception"
def run(self, **kwargs):
raise Exception(f"{self.name} event was called")

View file

@ -142,14 +142,14 @@ class Constellation:
royalnet_log.setLevel(log_level) royalnet_log.setLevel(log_level)
stream_handler = logging.StreamHandler() stream_handler = logging.StreamHandler()
if coloredlogs is not None: if coloredlogs is not None:
stream_handler.formatter = coloredlogs.ColoredFormatter("{asctime}\t| {processName}\t| {levelname}\t|" stream_handler.formatter = coloredlogs.ColoredFormatter("{asctime}\t| {processName}\t| {name}\t| {message}",
" {name}\t| {message}", style="{") style="{")
else: else:
stream_handler.formatter = logging.Formatter("{asctime}\t| {processName}\t| {levelname}\t| {name}\t| {message}", stream_handler.formatter = logging.Formatter("{asctime}\t| {processName}\t| {name}\t| {message}",
style="{") style="{")
if len(royalnet_log.handlers) < 1: if len(royalnet_log.handlers) < 1:
royalnet_log.addHandler(stream_handler) royalnet_log.addHandler(stream_handler)
royalnet_log.debug("Logging: ready") log.debug("Logging: ready")
# Initialize Sentry on the process # Initialize Sentry on the process
if sentry_sdk is None: if sentry_sdk is None:
@ -172,7 +172,7 @@ class Constellation:
release=release) release=release)
log.info(f"Sentry: enabled (Royalnet {release})") log.info(f"Sentry: enabled (Royalnet {release})")
# Run the server # Run the server
log.info(f"Running Constellation on https://{address}:{port}/ ...") log.info(f"Running Constellation on https://{address}:{port}/...")
constellation.running = True constellation.running = True
try: try:
uvicorn.run(constellation.starlette, host=address, port=port, log_config=UVICORN_LOGGING_CONFIG) uvicorn.run(constellation.starlette, host=address, port=port, log_config=UVICORN_LOGGING_CONFIG)

View file

@ -1,3 +1,4 @@
import logging
import typing import typing
import re import re
import datetime import datetime
@ -7,6 +8,11 @@ import logging as _logging
from .package import Package from .package import Package
from .config import Config from .config import Config
try:
import coloredlogs
except ImportError:
coloredlogs = None
try: try:
import websockets import websockets
except ImportError: except ImportError:
@ -144,7 +150,10 @@ class Server:
if self.config.secure: if self.config.secure:
raise Exception("Secure servers aren't supported yet") raise Exception("Secure servers aren't supported yet")
log.debug(f"Serving on {self.config.url}") log.debug(f"Serving on {self.config.url}")
self.loop.run_until_complete(self.run()) try:
self.loop.run_until_complete(self.run())
except OSError as e:
log.fatal(f"OSError: {e}")
self.loop.run_forever() self.loop.run_forever()
async def run(self): async def run(self):
@ -153,7 +162,20 @@ class Server:
port=self.config.port, port=self.config.port,
loop=self.loop) loop=self.loop)
def run_blocking(self): def run_blocking(self, log_level):
# Initialize logging, as Windows doesn't have fork
royalnet_log: logging.Logger = logging.getLogger("royalnet")
royalnet_log.setLevel(log_level)
stream_handler = logging.StreamHandler()
if coloredlogs is not None:
stream_handler.formatter = coloredlogs.ColoredFormatter("{asctime}\t| {processName}\t| {name}\t| {message}",
style="{")
else:
stream_handler.formatter = logging.Formatter("{asctime}\t| {processName}\t| {name}\t| {message}",
style="{")
if len(royalnet_log.handlers) < 1:
royalnet_log.addHandler(stream_handler)
log.debug("Logging: ready")
if self.loop is None: if self.loop is None:
self.loop = asyncio.get_event_loop() self.loop = asyncio.get_event_loop()
self.serve() self.serve()

View file

@ -1,4 +1,6 @@
import logging import logging
import sys
import traceback
from asyncio import Task, AbstractEventLoop, get_event_loop from asyncio import Task, AbstractEventLoop, get_event_loop
from typing import Type, Optional, Awaitable, Dict, List, Any, Callable, Union, Set from typing import Type, Optional, Awaitable, Dict, List, Any, Callable, Union, Set
from keyring import get_password from keyring import get_password
@ -161,22 +163,25 @@ class Serf:
request: Request = Request(handler=event_name, data=kwargs) request: Request = Request(handler=event_name, data=kwargs)
response: Response = await self.herald.request(destination=destination, request=request) response: Response = await self.herald.request(destination=destination, request=request)
if isinstance(response, ResponseFailure): if isinstance(response, ResponseFailure):
# TODO: pretty sure there's a better way to do this if response.name == "no_event":
if response.extra_info["type"] == "CommandError": raise CommandError(f"There is no event named {event_name} in {destination}.")
raise CommandError(response.extra_info["message"]) elif response.name == "exception_in_event":
elif response.extra_info["type"] == "UserError": # TODO: pretty sure there's a better way to do this
raise UserError(response.extra_info["message"]) if response.extra_info["type"] == "CommandError":
elif response.extra_info["type"] == "InvalidInputError": raise CommandError(response.extra_info["message"])
raise InvalidInputError(response.extra_info["message"]) elif response.extra_info["type"] == "UserError":
elif response.extra_info["type"] == "UnsupportedError": raise UserError(response.extra_info["message"])
raise UnsupportedError(response.extra_info["message"]) elif response.extra_info["type"] == "InvalidInputError":
elif response.extra_info["type"] == "ConfigurationError": raise InvalidInputError(response.extra_info["message"])
raise ConfigurationError(response.extra_info["message"]) elif response.extra_info["type"] == "UnsupportedError":
elif response.extra_info["type"] == "ExternalError": raise UnsupportedError(response.extra_info["message"])
raise ExternalError(response.extra_info["message"]) elif response.extra_info["type"] == "ConfigurationError":
else: raise ConfigurationError(response.extra_info["message"])
raise TypeError(f"Herald action call returned invalid error:\n" elif response.extra_info["type"] == "ExternalError":
f"[p]{response}[/p]") raise ExternalError(response.extra_info["message"])
else:
raise TypeError(f"Herald action call returned invalid error:\n"
f"[p]{response}[/p]")
elif isinstance(response, ResponseSuccess): elif isinstance(response, ResponseSuccess):
return response.data return response.data
else: else:
@ -249,6 +254,7 @@ class Serf:
response_data = await event.run(**message.data) response_data = await event.run(**message.data)
return ResponseSuccess(data=response_data) return ResponseSuccess(data=response_data)
except Exception as e: except Exception as e:
self.sentry_exc(e)
return ResponseFailure("exception_in_event", return ResponseFailure("exception_in_event",
f"An exception was raised in the event for '{message.handler}'.", f"An exception was raised in the event for '{message.handler}'.",
extra_info={ extra_info={
@ -273,11 +279,19 @@ class Serf:
release=release) release=release)
log.info(f"Sentry: enabled (Royalnet {release})") log.info(f"Sentry: enabled (Royalnet {release})")
# noinspection PyUnreachableCode
@staticmethod @staticmethod
def sentry_exc(exc: Exception): def sentry_exc(exc: Exception,
level: str = "error"):
if sentry_sdk is not None: if sentry_sdk is not None:
sentry_sdk.capture_exception(exc) with sentry_sdk.configure_scope() as scope:
log.error(f"Captured error: {exc}") scope.set_level(level)
sentry_sdk.capture_exception(exc)
log.log(level, f"Captured {level}: {exc}")
# If started in debug mode (without -O), raise the exception, allowing you to see its source
if __debug__:
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
def get_secret(self, username: str): def get_secret(self, username: str):
"""Get a Royalnet secret from the keyring. """Get a Royalnet secret from the keyring.
@ -325,14 +339,14 @@ class Serf:
royalnet_log.setLevel(log_level) royalnet_log.setLevel(log_level)
stream_handler = logging.StreamHandler() stream_handler = logging.StreamHandler()
if coloredlogs is not None: if coloredlogs is not None:
stream_handler.formatter = coloredlogs.ColoredFormatter("{asctime}\t| {processName}\t| {levelname}\t| {name}\t|" stream_handler.formatter = coloredlogs.ColoredFormatter("{asctime}\t| {processName}\t| {name}\t| {message}",
" {message}", style="{") style="{")
else: else:
stream_handler.formatter = Formatter("{asctime}\t| {processName}\t| {levelname}\t| {name}\t| {message}", stream_handler.formatter = logging.Formatter("{asctime}\t| {processName}\t| {name}\t| {message}",
style="{") style="{")
if len(royalnet_log.handlers) < 1: if len(royalnet_log.handlers) < 1:
royalnet_log.addHandler(stream_handler) royalnet_log.addHandler(stream_handler)
royalnet_log.debug("Logging: ready") log.debug("Logging: ready")
if sentry_sdk is None: if sentry_sdk is None:
log.info("Sentry: not installed") log.info("Sentry: not installed")
@ -347,5 +361,4 @@ class Serf:
try: try:
serf.loop.run_until_complete(serf.run()) serf.loop.run_until_complete(serf.run())
except Exception as e: except Exception as e:
log.error(f"Uncaught exception: {e}") serf.sentry_exc(e, level="fatal")
serf.sentry_exc(e)