2019-08-28 13:18:53 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2019 The Matrix.org Foundation C.I.C.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
import os.path
|
2020-10-29 12:27:37 +01:00
|
|
|
from typing import Any, Dict, Generator, Optional, Tuple
|
2019-08-28 13:18:53 +02:00
|
|
|
|
2020-10-29 12:27:37 +01:00
|
|
|
from constantly import NamedConstant, Names
|
2019-08-28 13:18:53 +02:00
|
|
|
|
|
|
|
from synapse.config._base import ConfigError
|
|
|
|
|
|
|
|
|
|
|
|
class DrainType(Names):
|
|
|
|
CONSOLE = NamedConstant()
|
|
|
|
CONSOLE_JSON = NamedConstant()
|
|
|
|
CONSOLE_JSON_TERSE = NamedConstant()
|
|
|
|
FILE = NamedConstant()
|
|
|
|
FILE_JSON = NamedConstant()
|
|
|
|
NETWORK_JSON_TERSE = NamedConstant()
|
|
|
|
|
|
|
|
|
2020-10-29 12:27:37 +01:00
|
|
|
DEFAULT_LOGGERS = {"synapse": {"level": "info"}}
|
2019-08-28 13:18:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
def parse_drain_configs(
|
2019-10-31 16:43:24 +01:00
|
|
|
drains: dict,
|
2020-10-29 12:27:37 +01:00
|
|
|
) -> Generator[Tuple[str, Dict[str, Any]], None, None]:
|
2019-08-28 13:18:53 +02:00
|
|
|
"""
|
|
|
|
Parse the drain configurations.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
drains (dict): A list of drain configurations.
|
|
|
|
|
|
|
|
Yields:
|
2020-10-29 12:27:37 +01:00
|
|
|
dict instances representing a logging handler.
|
2019-08-28 13:18:53 +02:00
|
|
|
|
|
|
|
Raises:
|
|
|
|
ConfigError: If any of the drain configuration items are invalid.
|
|
|
|
"""
|
2020-10-29 12:27:37 +01:00
|
|
|
|
2019-08-28 13:18:53 +02:00
|
|
|
for name, config in drains.items():
|
|
|
|
if "type" not in config:
|
|
|
|
raise ConfigError("Logging drains require a 'type' key.")
|
|
|
|
|
|
|
|
try:
|
|
|
|
logging_type = DrainType.lookupByName(config["type"].upper())
|
|
|
|
except ValueError:
|
|
|
|
raise ConfigError(
|
|
|
|
"%s is not a known logging drain type." % (config["type"],)
|
|
|
|
)
|
|
|
|
|
2020-10-29 12:27:37 +01:00
|
|
|
# Either use the default formatter or the tersejson one.
|
2021-02-16 23:32:34 +01:00
|
|
|
if logging_type in (
|
|
|
|
DrainType.CONSOLE_JSON,
|
|
|
|
DrainType.FILE_JSON,
|
|
|
|
):
|
2020-10-29 12:27:37 +01:00
|
|
|
formatter = "json" # type: Optional[str]
|
|
|
|
elif logging_type in (
|
|
|
|
DrainType.CONSOLE_JSON_TERSE,
|
|
|
|
DrainType.NETWORK_JSON_TERSE,
|
|
|
|
):
|
|
|
|
formatter = "tersejson"
|
|
|
|
else:
|
|
|
|
# A formatter of None implies using the default formatter.
|
|
|
|
formatter = None
|
|
|
|
|
2019-08-28 13:18:53 +02:00
|
|
|
if logging_type in [
|
|
|
|
DrainType.CONSOLE,
|
|
|
|
DrainType.CONSOLE_JSON,
|
|
|
|
DrainType.CONSOLE_JSON_TERSE,
|
|
|
|
]:
|
|
|
|
location = config.get("location")
|
|
|
|
if location is None or location not in ["stdout", "stderr"]:
|
|
|
|
raise ConfigError(
|
|
|
|
(
|
|
|
|
"The %s drain needs the 'location' key set to "
|
|
|
|
"either 'stdout' or 'stderr'."
|
|
|
|
)
|
|
|
|
% (logging_type,)
|
|
|
|
)
|
|
|
|
|
2020-10-29 12:27:37 +01:00
|
|
|
yield name, {
|
|
|
|
"class": "logging.StreamHandler",
|
|
|
|
"formatter": formatter,
|
|
|
|
"stream": "ext://sys." + location,
|
|
|
|
}
|
2019-08-28 13:18:53 +02:00
|
|
|
|
|
|
|
elif logging_type in [DrainType.FILE, DrainType.FILE_JSON]:
|
|
|
|
if "location" not in config:
|
|
|
|
raise ConfigError(
|
|
|
|
"The %s drain needs the 'location' key set." % (logging_type,)
|
|
|
|
)
|
|
|
|
|
|
|
|
location = config.get("location")
|
|
|
|
if os.path.abspath(location) != location:
|
|
|
|
raise ConfigError(
|
|
|
|
"File paths need to be absolute, '%s' is a relative path"
|
|
|
|
% (location,)
|
|
|
|
)
|
2020-10-29 12:27:37 +01:00
|
|
|
|
|
|
|
yield name, {
|
|
|
|
"class": "logging.FileHandler",
|
|
|
|
"formatter": formatter,
|
|
|
|
"filename": location,
|
|
|
|
}
|
2019-08-28 13:18:53 +02:00
|
|
|
|
|
|
|
elif logging_type in [DrainType.NETWORK_JSON_TERSE]:
|
|
|
|
host = config.get("host")
|
|
|
|
port = config.get("port")
|
|
|
|
maximum_buffer = config.get("maximum_buffer", 1000)
|
2020-10-29 12:27:37 +01:00
|
|
|
|
|
|
|
yield name, {
|
|
|
|
"class": "synapse.logging.RemoteHandler",
|
|
|
|
"formatter": formatter,
|
|
|
|
"host": host,
|
|
|
|
"port": port,
|
|
|
|
"maximum_buffer": maximum_buffer,
|
|
|
|
}
|
2019-08-28 13:18:53 +02:00
|
|
|
|
|
|
|
else:
|
|
|
|
raise ConfigError(
|
|
|
|
"The %s drain type is currently not implemented."
|
|
|
|
% (config["type"].upper(),)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-02-16 23:32:34 +01:00
|
|
|
def setup_structured_logging(
|
|
|
|
log_config: dict,
|
|
|
|
) -> dict:
|
2019-11-25 17:45:50 +01:00
|
|
|
"""
|
2020-10-29 12:27:37 +01:00
|
|
|
Convert a legacy structured logging configuration (from Synapse < v1.23.0)
|
|
|
|
to one compatible with the new standard library handlers.
|
2019-08-28 13:18:53 +02:00
|
|
|
"""
|
|
|
|
if "drains" not in log_config:
|
|
|
|
raise ConfigError("The logging configuration requires a list of drains.")
|
|
|
|
|
2020-10-29 12:27:37 +01:00
|
|
|
new_config = {
|
|
|
|
"version": 1,
|
|
|
|
"formatters": {
|
|
|
|
"json": {"class": "synapse.logging.JsonFormatter"},
|
|
|
|
"tersejson": {"class": "synapse.logging.TerseJsonFormatter"},
|
|
|
|
},
|
|
|
|
"handlers": {},
|
|
|
|
"loggers": log_config.get("loggers", DEFAULT_LOGGERS),
|
|
|
|
"root": {"handlers": []},
|
|
|
|
}
|
2019-08-28 13:18:53 +02:00
|
|
|
|
2020-10-29 12:27:37 +01:00
|
|
|
for handler_name, handler in parse_drain_configs(log_config["drains"]):
|
|
|
|
new_config["handlers"][handler_name] = handler
|
2019-08-28 13:18:53 +02:00
|
|
|
|
2020-10-29 12:27:37 +01:00
|
|
|
# Add each handler to the root logger.
|
|
|
|
new_config["root"]["handlers"].append(handler_name)
|
2019-08-28 13:18:53 +02:00
|
|
|
|
2020-10-29 12:27:37 +01:00
|
|
|
return new_config
|