25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

224 lines
6.5 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import logging
  16. import logging.config
  17. import os
  18. import sys
  19. from string import Template
  20. import yaml
  21. from twisted.logger import STDLibLogObserver, globalLogBeginner
  22. import synapse
  23. from synapse.app import _base as appbase
  24. from synapse.logging._structured import (
  25. reload_structured_logging,
  26. setup_structured_logging,
  27. )
  28. from synapse.logging.context import LoggingContextFilter
  29. from synapse.util.versionstring import get_version_string
  30. from ._base import Config
  31. DEFAULT_LOG_CONFIG = Template(
  32. """
  33. version: 1
  34. formatters:
  35. precise:
  36. format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - \
  37. %(request)s - %(message)s'
  38. filters:
  39. context:
  40. (): synapse.logging.context.LoggingContextFilter
  41. request: ""
  42. handlers:
  43. file:
  44. class: logging.handlers.RotatingFileHandler
  45. formatter: precise
  46. filename: ${log_file}
  47. maxBytes: 104857600
  48. backupCount: 10
  49. filters: [context]
  50. encoding: utf8
  51. console:
  52. class: logging.StreamHandler
  53. formatter: precise
  54. filters: [context]
  55. loggers:
  56. synapse:
  57. level: INFO
  58. synapse.storage.SQL:
  59. # beware: increasing this to DEBUG will make synapse log sensitive
  60. # information such as access tokens.
  61. level: INFO
  62. root:
  63. level: INFO
  64. handlers: [file, console]
  65. """
  66. )
  67. class LoggingConfig(Config):
  68. def read_config(self, config, **kwargs):
  69. self.log_config = self.abspath(config.get("log_config"))
  70. self.no_redirect_stdio = config.get("no_redirect_stdio", False)
  71. def generate_config_section(self, config_dir_path, server_name, **kwargs):
  72. log_config = os.path.join(config_dir_path, server_name + ".log.config")
  73. return (
  74. """\
  75. ## Logging ##
  76. # A yaml python logging config file as described by
  77. # https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
  78. #
  79. log_config: "%(log_config)s"
  80. """
  81. % locals()
  82. )
  83. def read_arguments(self, args):
  84. if args.no_redirect_stdio is not None:
  85. self.no_redirect_stdio = args.no_redirect_stdio
  86. @staticmethod
  87. def add_arguments(parser):
  88. logging_group = parser.add_argument_group("logging")
  89. logging_group.add_argument(
  90. "-n",
  91. "--no-redirect-stdio",
  92. action="store_true",
  93. default=None,
  94. help="Do not redirect stdout/stderr to the log",
  95. )
  96. def generate_files(self, config, config_dir_path):
  97. log_config = config.get("log_config")
  98. if log_config and not os.path.exists(log_config):
  99. log_file = self.abspath("homeserver.log")
  100. print(
  101. "Generating log config file %s which will log to %s"
  102. % (log_config, log_file)
  103. )
  104. with open(log_config, "w") as log_config_file:
  105. log_config_file.write(DEFAULT_LOG_CONFIG.substitute(log_file=log_file))
  106. def _setup_stdlib_logging(config, log_config):
  107. """
  108. Set up Python stdlib logging.
  109. """
  110. if log_config is None:
  111. log_format = (
  112. "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s"
  113. " - %(message)s"
  114. )
  115. logger = logging.getLogger("")
  116. logger.setLevel(logging.INFO)
  117. logging.getLogger("synapse.storage.SQL").setLevel(logging.INFO)
  118. formatter = logging.Formatter(log_format)
  119. handler = logging.StreamHandler()
  120. handler.setFormatter(formatter)
  121. handler.addFilter(LoggingContextFilter(request=""))
  122. logger.addHandler(handler)
  123. else:
  124. logging.config.dictConfig(log_config)
  125. # Route Twisted's native logging through to the standard library logging
  126. # system.
  127. observer = STDLibLogObserver()
  128. def _log(event):
  129. if "log_text" in event:
  130. if event["log_text"].startswith("DNSDatagramProtocol starting on "):
  131. return
  132. if event["log_text"].startswith("(UDP Port "):
  133. return
  134. if event["log_text"].startswith("Timing out client"):
  135. return
  136. return observer(event)
  137. globalLogBeginner.beginLoggingTo(
  138. [_log], redirectStandardIO=not config.no_redirect_stdio
  139. )
  140. if not config.no_redirect_stdio:
  141. print("Redirected stdout/stderr to logs")
  142. def _reload_stdlib_logging(*args, log_config=None):
  143. logger = logging.getLogger("")
  144. if not log_config:
  145. logger.warn("Reloaded a blank config?")
  146. logging.config.dictConfig(log_config)
  147. def setup_logging(hs, config, use_worker_options=False):
  148. """
  149. Set up the logging subsystem.
  150. Args:
  151. config (LoggingConfig | synapse.config.workers.WorkerConfig):
  152. configuration data
  153. use_worker_options (bool): True to use the 'worker_log_config' option
  154. instead of 'log_config'.
  155. """
  156. log_config = config.worker_log_config if use_worker_options else config.log_config
  157. def read_config(*args, callback=None):
  158. if log_config is None:
  159. return None
  160. with open(log_config, "rb") as f:
  161. log_config_body = yaml.safe_load(f.read())
  162. if callback:
  163. callback(log_config=log_config_body)
  164. logging.info("Reloaded log config from %s due to SIGHUP", log_config)
  165. return log_config_body
  166. log_config_body = read_config()
  167. if log_config_body and log_config_body.get("structured") is True:
  168. setup_structured_logging(hs, config, log_config_body)
  169. appbase.register_sighup(read_config, callback=reload_structured_logging)
  170. else:
  171. _setup_stdlib_logging(config, log_config_body)
  172. appbase.register_sighup(read_config, callback=_reload_stdlib_logging)
  173. # make sure that the first thing we log is a thing we can grep backwards
  174. # for
  175. logging.warn("***** STARTING SERVER *****")
  176. logging.warn("Server %s version %s", sys.argv[0], get_version_string(synapse))
  177. logging.info("Server hostname: %s", config.server_name)