1
0
mirror of https://github.com/checktheroads/hyperglass synced 2024-05-11 05:55:08 +00:00

revamp logging

This commit is contained in:
checktheroads
2020-04-14 10:24:20 -07:00
parent 90725ed67f
commit 5f3c516f86
20 changed files with 202 additions and 165 deletions

View File

@@ -6,7 +6,6 @@ import copy
import json
import math
from pathlib import Path
from datetime import datetime
# Third Party
import yaml
@@ -14,10 +13,15 @@ from aiofile import AIOFile
from pydantic import ValidationError
# Project
from hyperglass.util import log, check_path, set_app_path
from hyperglass.log import (
log,
set_log_level,
enable_file_logging,
enable_syslog_logging,
)
from hyperglass.util import check_path, set_app_path
from hyperglass.constants import (
CREDIT,
LOG_HANDLER,
DEFAULT_HELP,
DEFAULT_TERMS,
DEFAULT_DETAILS,
@@ -82,66 +86,6 @@ STATIC_PATH = CONFIG_PATH / "static"
CONFIG_MAIN, CONFIG_DEVICES, CONFIG_COMMANDS = _check_config_files(CONFIG_PATH)
def _set_log_level(debug):
"""Set log level based on debug state.
Arguments:
debug {bool} -- Debug state from config file
Returns:
{bool} -- True
"""
stdout_handler = LOG_HANDLER.copy()
if debug:
log_level = "DEBUG"
stdout_handler["level"] = log_level
os.environ["HYPERGLASS_LOG_LEVEL"] = log_level
log.configure(handlers=[stdout_handler])
if debug:
log.debug("Debugging enabled")
return True
def _set_file_logging(log_directory, log_format, log_max_size):
"""Set up file-based logging from configuration parameters."""
if log_format == "json":
log_file_name = "hyperglass_log.json"
structured = True
else:
log_file_name = "hyperglass_log.log"
structured = False
log_file = log_directory / log_file_name
if log_format == "text":
now_str = "hyperglass logs for " + datetime.utcnow().strftime(
"%B %d, %Y beginning at %H:%M:%S UTC"
)
now_str_y = len(now_str) + 6
now_str_x = len(now_str) + 4
log_break = (
"#" * now_str_y,
"\n#" + " " * now_str_x + "#\n",
"# ",
now_str,
" #",
"\n#" + " " * now_str_x + "#\n",
"#" * now_str_y,
)
with log_file.open("a+") as lf:
lf.write(f'\n\n{"".join(log_break)}\n\n')
log.add(log_file, rotation=log_max_size, serialize=structured)
log.debug("Logging to file enabled")
return True
def _config_required(config_path: Path) -> dict:
try:
with config_path.open("r") as cf:
@@ -224,11 +168,8 @@ async def _config_devices():
user_config = _config_optional(CONFIG_MAIN)
# Logging Config
_debug = user_config.get("debug", True)
# Read raw debug value from config to enable debugging quickly.
_set_log_level(_debug)
set_log_level(logger=log, debug=user_config.get("debug", True))
_user_commands = _config_optional(CONFIG_COMMANDS)
_user_devices = _config_required(CONFIG_DEVICES)
@@ -247,13 +188,25 @@ except ValidationError as validation_errors:
error_msg=error["msg"],
)
# Re-evaluate debug state after config is validated
set_log_level(logger=log, debug=params.debug)
# Set up file logging once configuration parameters are initialized.
_set_file_logging(
log_directory=params.log_directory,
log_format=params.log_format,
log_max_size=params.log_max_size,
enable_file_logging(
logger=log,
log_directory=params.logging.directory,
log_format=params.logging.format,
log_max_size=params.logging.max_size,
)
# Set up syslog logging if enabled.
if params.logging.syslog is not None and params.logging.syslog.enable:
enable_syslog_logging(
logger=log,
syslog_host=params.logging.syslog.host,
syslog_port=params.logging.syslog.port,
)
# Perform post-config initialization string formatting or other
# functions that require access to other config levels. E.g.,
# something in 'params.web.text' needs to be formatted with a value
@@ -288,10 +241,6 @@ except KeyError:
pass
# Re-evaluate debug state after config is validated
_set_log_level(params.debug)
def _build_frontend_networks():
"""Build filtered JSON structure of networks for frontend.

View File

@@ -1,7 +1,7 @@
"""Markdown processing utility functions."""
# Project
from hyperglass.util import log
from hyperglass.log import log
def _get_file(path_obj):

View File

@@ -0,0 +1,28 @@
"""Validate logging configuration."""
# Standard Library
from typing import Optional
from pathlib import Path
# Third Party
from pydantic import ByteSize, StrictInt, StrictStr, StrictBool, DirectoryPath, constr
# Project
from hyperglass.configuration.models._utils import HyperglassModel
class Syslog(HyperglassModel):
"""Validation model for syslog configuration."""
enable: StrictBool = True
host: StrictStr
port: StrictInt = 514
class Logging(HyperglassModel):
"""Validation model for logging configuration."""
directory: DirectoryPath = Path("/tmp") # noqa: S108
format: constr(regex=r"(text|json)") = "text"
syslog: Optional[Syslog]
max_size: ByteSize = "50MB"

View File

@@ -1,11 +1,9 @@
"""Validate error message configuration variables."""
# Third Party
# Third Party Imports
from pydantic import Field, StrictStr
# Project
# Project Imports
from hyperglass.configuration.models._utils import HyperglassModel

View File

@@ -2,17 +2,14 @@
# Standard Library
from typing import List, Union, Optional
from pathlib import Path
from ipaddress import ip_address
# Third Party
from pydantic import (
Field,
ByteSize,
StrictInt,
StrictStr,
StrictBool,
DirectoryPath,
IPvAnyAddress,
constr,
validator,
@@ -23,6 +20,7 @@ from hyperglass.configuration.models.web import Web
from hyperglass.configuration.models.docs import Docs
from hyperglass.configuration.models.cache import Cache
from hyperglass.configuration.models._utils import IntFloat, HyperglassModel
from hyperglass.configuration.models.logging import Logging
from hyperglass.configuration.models.queries import Queries
from hyperglass.configuration.models.messages import Messages
@@ -98,19 +96,6 @@ class Params(HyperglassModel):
title="Listen Port",
description="Local TCP port the hyperglass application listens on to serve web traffic.",
)
log_directory: DirectoryPath = Field(
Path("/tmp"), # noqa: S108
title="Log Directory",
description="Path to a directory, to which hyperglass can write logs. If none is set, hyperglass will write logs to a file located at `/tmp/`, with a uniquely generated name for each time hyperglass is started.",
)
log_format: constr(regex=r"(text|json)") = Field(
"text", title="Log Format", description="Format for logs written to a file."
)
log_max_size: ByteSize = Field(
"50MB",
title="Maximum Log File Size",
description="Maximum storage space log file may consume.",
)
cors_origins: List[StrictStr] = Field(
[],
title="Cross-Origin Resource Sharing",
@@ -125,6 +110,7 @@ class Params(HyperglassModel):
# Sub Level Params
cache: Cache = Cache()
docs: Docs = Docs()
logging: Logging = Logging()
messages: Messages = Messages()
queries: Queries = Queries()
web: Web = Web()

View File

@@ -10,7 +10,8 @@ from pathlib import Path
from pydantic import StrictInt, StrictStr, validator
# Project
from hyperglass.util import log, clean_name
from hyperglass.log import log
from hyperglass.util import clean_name
from hyperglass.constants import SCRAPE_HELPERS, TRANSPORT_REST, TRANSPORT_SCRAPE
from hyperglass.exceptions import ConfigError, UnsupportedDevice
from hyperglass.configuration.models.ssl import Ssl