2014-08-31 17:06:39 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
2016-01-07 05:26:29 +01:00
|
|
|
# Copyright 2014-2016 OpenMarket Ltd
|
2014-08-31 17:06:39 +02:00
|
|
|
#
|
|
|
|
# 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.
|
2020-01-03 18:11:29 +01:00
|
|
|
import argparse
|
2014-08-31 17:06:39 +02:00
|
|
|
import logging
|
|
|
|
import logging.config
|
2015-04-30 17:52:57 +02:00
|
|
|
import os
|
2018-06-20 16:33:14 +02:00
|
|
|
import sys
|
2018-07-09 08:09:20 +02:00
|
|
|
from string import Template
|
2015-04-30 17:52:57 +02:00
|
|
|
|
2018-06-20 16:33:14 +02:00
|
|
|
import yaml
|
|
|
|
|
2019-09-12 18:29:55 +02:00
|
|
|
from twisted.logger import (
|
|
|
|
ILogObserver,
|
|
|
|
LogBeginner,
|
|
|
|
STDLibLogObserver,
|
|
|
|
globalLogBeginner,
|
|
|
|
)
|
2018-07-09 08:09:20 +02:00
|
|
|
|
2018-06-20 16:33:14 +02:00
|
|
|
import synapse
|
2019-02-08 18:25:57 +01:00
|
|
|
from synapse.app import _base as appbase
|
2019-08-28 13:18:53 +02:00
|
|
|
from synapse.logging._structured import (
|
|
|
|
reload_structured_logging,
|
|
|
|
setup_structured_logging,
|
|
|
|
)
|
2019-07-03 16:07:04 +02:00
|
|
|
from synapse.logging.context import LoggingContextFilter
|
2018-06-20 16:33:14 +02:00
|
|
|
from synapse.util.versionstring import get_version_string
|
2018-07-09 08:09:20 +02:00
|
|
|
|
2020-01-03 18:11:29 +01:00
|
|
|
from ._base import Config, ConfigError
|
2015-04-30 17:52:57 +02:00
|
|
|
|
2019-06-20 11:32:02 +02:00
|
|
|
DEFAULT_LOG_CONFIG = Template(
|
2020-01-03 18:14:00 +01:00
|
|
|
"""\
|
|
|
|
# Log configuration for Synapse.
|
|
|
|
#
|
|
|
|
# This is a YAML file containing a standard Python logging configuration
|
|
|
|
# dictionary. See [1] for details on the valid settings.
|
|
|
|
#
|
|
|
|
# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
|
|
|
|
|
2015-04-30 17:52:57 +02:00
|
|
|
version: 1
|
|
|
|
|
|
|
|
formatters:
|
2018-01-09 12:27:19 +01:00
|
|
|
precise:
|
|
|
|
format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - \
|
|
|
|
%(request)s - %(message)s'
|
2015-04-30 17:52:57 +02:00
|
|
|
|
|
|
|
filters:
|
2018-01-09 12:27:19 +01:00
|
|
|
context:
|
2019-07-03 16:07:04 +02:00
|
|
|
(): synapse.logging.context.LoggingContextFilter
|
2018-01-09 12:27:19 +01:00
|
|
|
request: ""
|
2015-04-30 17:52:57 +02:00
|
|
|
|
|
|
|
handlers:
|
2018-01-09 12:27:19 +01:00
|
|
|
file:
|
|
|
|
class: logging.handlers.RotatingFileHandler
|
|
|
|
formatter: precise
|
|
|
|
filename: ${log_file}
|
|
|
|
maxBytes: 104857600
|
|
|
|
backupCount: 10
|
|
|
|
filters: [context]
|
2018-11-02 16:28:07 +01:00
|
|
|
encoding: utf8
|
2018-01-09 12:27:19 +01:00
|
|
|
console:
|
|
|
|
class: logging.StreamHandler
|
|
|
|
formatter: precise
|
|
|
|
filters: [context]
|
2015-04-30 17:52:57 +02:00
|
|
|
|
|
|
|
loggers:
|
|
|
|
synapse.storage.SQL:
|
2017-03-10 16:23:20 +01:00
|
|
|
# beware: increasing this to DEBUG will make synapse log sensitive
|
|
|
|
# information such as access tokens.
|
2015-04-30 17:52:57 +02:00
|
|
|
level: INFO
|
|
|
|
|
|
|
|
root:
|
|
|
|
level: INFO
|
|
|
|
handlers: [file, console]
|
2019-10-18 13:34:33 +02:00
|
|
|
|
|
|
|
disable_existing_loggers: false
|
2019-06-20 11:32:02 +02:00
|
|
|
"""
|
|
|
|
)
|
2014-08-31 17:06:39 +02:00
|
|
|
|
2020-01-03 18:11:29 +01:00
|
|
|
LOG_FILE_ERROR = """\
|
|
|
|
Support for the log_file configuration option and --log-file command-line option was
|
|
|
|
removed in Synapse 1.3.0. You should instead set up a separate log configuration file.
|
|
|
|
"""
|
|
|
|
|
2014-10-30 11:13:46 +01:00
|
|
|
|
2014-08-31 17:06:39 +02:00
|
|
|
class LoggingConfig(Config):
|
2019-10-10 10:39:35 +02:00
|
|
|
section = "logging"
|
|
|
|
|
2019-06-24 12:34:45 +02:00
|
|
|
def read_config(self, config, **kwargs):
|
2020-01-03 18:11:29 +01:00
|
|
|
if config.get("log_file"):
|
|
|
|
raise ConfigError(LOG_FILE_ERROR)
|
2015-04-30 05:24:44 +02:00
|
|
|
self.log_config = self.abspath(config.get("log_config"))
|
2019-07-18 17:40:08 +02:00
|
|
|
self.no_redirect_stdio = config.get("no_redirect_stdio", False)
|
2015-04-30 05:24:44 +02:00
|
|
|
|
2019-06-22 01:00:20 +02:00
|
|
|
def generate_config_section(self, config_dir_path, server_name, **kwargs):
|
2018-12-21 16:04:57 +01:00
|
|
|
log_config = os.path.join(config_dir_path, server_name + ".log.config")
|
2019-06-20 11:32:02 +02:00
|
|
|
return (
|
|
|
|
"""\
|
2019-03-04 18:14:58 +01:00
|
|
|
## Logging ##
|
|
|
|
|
2019-08-28 20:08:32 +02:00
|
|
|
# A yaml python logging config file as described by
|
|
|
|
# https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
|
2019-02-19 14:54:29 +01:00
|
|
|
#
|
2015-04-30 17:52:57 +02:00
|
|
|
log_config: "%(log_config)s"
|
2019-06-20 11:32:02 +02:00
|
|
|
"""
|
|
|
|
% locals()
|
|
|
|
)
|
2015-04-30 05:24:44 +02:00
|
|
|
|
|
|
|
def read_arguments(self, args):
|
2017-03-10 16:38:29 +01:00
|
|
|
if args.no_redirect_stdio is not None:
|
|
|
|
self.no_redirect_stdio = args.no_redirect_stdio
|
2020-01-03 18:11:29 +01:00
|
|
|
if args.log_file is not None:
|
|
|
|
raise ConfigError(LOG_FILE_ERROR)
|
2015-04-30 05:24:44 +02:00
|
|
|
|
2019-07-15 14:15:34 +02:00
|
|
|
@staticmethod
|
|
|
|
def add_arguments(parser):
|
2014-08-31 17:06:39 +02:00
|
|
|
logging_group = parser.add_argument_group("logging")
|
2017-03-10 16:38:29 +01:00
|
|
|
logging_group.add_argument(
|
2019-06-20 11:32:02 +02:00
|
|
|
"-n",
|
|
|
|
"--no-redirect-stdio",
|
|
|
|
action="store_true",
|
|
|
|
default=None,
|
|
|
|
help="Do not redirect stdout/stderr to the log",
|
2017-03-10 16:38:29 +01:00
|
|
|
)
|
2014-08-31 17:06:39 +02:00
|
|
|
|
2020-01-03 18:11:29 +01:00
|
|
|
logging_group.add_argument(
|
|
|
|
"-f", "--log-file", dest="log_file", help=argparse.SUPPRESS,
|
|
|
|
)
|
|
|
|
|
2019-06-22 00:39:08 +02:00
|
|
|
def generate_files(self, config, config_dir_path):
|
2015-04-30 17:52:57 +02:00
|
|
|
log_config = config.get("log_config")
|
|
|
|
if log_config and not os.path.exists(log_config):
|
2018-01-09 12:28:33 +01:00
|
|
|
log_file = self.abspath("homeserver.log")
|
2019-06-21 18:14:56 +02:00
|
|
|
print(
|
|
|
|
"Generating log config file %s which will log to %s"
|
|
|
|
% (log_config, log_file)
|
|
|
|
)
|
2018-04-28 12:29:02 +02:00
|
|
|
with open(log_config, "w") as log_config_file:
|
2019-06-20 11:32:02 +02:00
|
|
|
log_config_file.write(DEFAULT_LOG_CONFIG.substitute(log_file=log_file))
|
2015-04-30 17:52:57 +02:00
|
|
|
|
2016-06-16 12:06:12 +02:00
|
|
|
|
2019-09-12 18:29:55 +02:00
|
|
|
def _setup_stdlib_logging(config, log_config, logBeginner: LogBeginner):
|
2019-08-28 13:18:53 +02:00
|
|
|
"""
|
|
|
|
Set up Python stdlib logging.
|
2017-03-10 16:16:50 +01:00
|
|
|
"""
|
2017-10-26 17:45:20 +02:00
|
|
|
if log_config is None:
|
2019-07-18 17:40:08 +02:00
|
|
|
log_format = (
|
|
|
|
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s"
|
|
|
|
" - %(message)s"
|
|
|
|
)
|
2016-06-16 12:06:12 +02:00
|
|
|
|
2019-06-20 11:32:02 +02:00
|
|
|
logger = logging.getLogger("")
|
2019-07-18 17:40:08 +02:00
|
|
|
logger.setLevel(logging.INFO)
|
|
|
|
logging.getLogger("synapse.storage.SQL").setLevel(logging.INFO)
|
2016-06-16 12:06:12 +02:00
|
|
|
|
|
|
|
formatter = logging.Formatter(log_format)
|
2017-10-26 17:45:20 +02:00
|
|
|
|
2019-07-18 17:40:08 +02:00
|
|
|
handler = logging.StreamHandler()
|
2016-06-16 12:06:12 +02:00
|
|
|
handler.setFormatter(formatter)
|
|
|
|
handler.addFilter(LoggingContextFilter(request=""))
|
|
|
|
logger.addHandler(handler)
|
|
|
|
else:
|
2019-08-28 13:18:53 +02:00
|
|
|
logging.config.dictConfig(log_config)
|
2019-06-20 11:32:02 +02:00
|
|
|
|
2019-08-28 13:18:53 +02:00
|
|
|
# Route Twisted's native logging through to the standard library logging
|
|
|
|
# system.
|
2016-12-30 12:05:37 +01:00
|
|
|
observer = STDLibLogObserver()
|
2018-09-13 11:59:32 +02:00
|
|
|
|
|
|
|
def _log(event):
|
|
|
|
|
|
|
|
if "log_text" in event:
|
|
|
|
if event["log_text"].startswith("DNSDatagramProtocol starting on "):
|
|
|
|
return
|
|
|
|
|
|
|
|
if event["log_text"].startswith("(UDP Port "):
|
|
|
|
return
|
|
|
|
|
|
|
|
if event["log_text"].startswith("Timing out client"):
|
|
|
|
return
|
|
|
|
|
|
|
|
return observer(event)
|
|
|
|
|
2019-09-12 18:29:55 +02:00
|
|
|
logBeginner.beginLoggingTo([_log], redirectStandardIO=not config.no_redirect_stdio)
|
2019-02-14 18:10:36 +01:00
|
|
|
if not config.no_redirect_stdio:
|
|
|
|
print("Redirected stdout/stderr to logs")
|
2019-08-28 13:18:53 +02:00
|
|
|
|
2019-09-12 18:29:55 +02:00
|
|
|
return observer
|
|
|
|
|
2019-08-28 13:18:53 +02:00
|
|
|
|
|
|
|
def _reload_stdlib_logging(*args, log_config=None):
|
|
|
|
logger = logging.getLogger("")
|
|
|
|
|
|
|
|
if not log_config:
|
2019-10-31 11:23:24 +01:00
|
|
|
logger.warning("Reloaded a blank config?")
|
2019-08-28 13:18:53 +02:00
|
|
|
|
|
|
|
logging.config.dictConfig(log_config)
|
|
|
|
|
|
|
|
|
2019-09-12 18:29:55 +02:00
|
|
|
def setup_logging(
|
|
|
|
hs, config, use_worker_options=False, logBeginner: LogBeginner = globalLogBeginner
|
|
|
|
) -> ILogObserver:
|
2019-08-28 13:18:53 +02:00
|
|
|
"""
|
|
|
|
Set up the logging subsystem.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
config (LoggingConfig | synapse.config.workers.WorkerConfig):
|
|
|
|
configuration data
|
|
|
|
|
|
|
|
use_worker_options (bool): True to use the 'worker_log_config' option
|
|
|
|
instead of 'log_config'.
|
2019-09-12 18:29:55 +02:00
|
|
|
|
|
|
|
logBeginner: The Twisted logBeginner to use.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
The "root" Twisted Logger observer, suitable for sending logs to from a
|
|
|
|
Logger instance.
|
2019-08-28 13:18:53 +02:00
|
|
|
"""
|
|
|
|
log_config = config.worker_log_config if use_worker_options else config.log_config
|
|
|
|
|
|
|
|
def read_config(*args, callback=None):
|
|
|
|
if log_config is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
with open(log_config, "rb") as f:
|
|
|
|
log_config_body = yaml.safe_load(f.read())
|
|
|
|
|
|
|
|
if callback:
|
|
|
|
callback(log_config=log_config_body)
|
|
|
|
logging.info("Reloaded log config from %s due to SIGHUP", log_config)
|
|
|
|
|
|
|
|
return log_config_body
|
|
|
|
|
|
|
|
log_config_body = read_config()
|
|
|
|
|
|
|
|
if log_config_body and log_config_body.get("structured") is True:
|
2019-09-12 18:29:55 +02:00
|
|
|
logger = setup_structured_logging(
|
|
|
|
hs, config, log_config_body, logBeginner=logBeginner
|
|
|
|
)
|
2019-08-28 13:18:53 +02:00
|
|
|
appbase.register_sighup(read_config, callback=reload_structured_logging)
|
|
|
|
else:
|
2019-09-12 18:29:55 +02:00
|
|
|
logger = _setup_stdlib_logging(config, log_config_body, logBeginner=logBeginner)
|
2019-08-28 13:18:53 +02:00
|
|
|
appbase.register_sighup(read_config, callback=_reload_stdlib_logging)
|
|
|
|
|
|
|
|
# make sure that the first thing we log is a thing we can grep backwards
|
|
|
|
# for
|
2019-11-01 13:03:44 +01:00
|
|
|
logging.warning("***** STARTING SERVER *****")
|
|
|
|
logging.warning("Server %s version %s", sys.argv[0], get_version_string(synapse))
|
2019-08-28 13:18:53 +02:00
|
|
|
logging.info("Server hostname: %s", config.server_name)
|
2020-05-22 17:11:35 +02:00
|
|
|
logging.info("Instance name: %s", hs.get_instance_name())
|
2019-09-12 18:29:55 +02:00
|
|
|
|
|
|
|
return logger
|