hat.syslog.server.main
Syslog Server main module
1"""Syslog Server main module""" 2 3from pathlib import Path 4import argparse 5import asyncio 6import contextlib 7import logging.config 8import sys 9import typing 10 11import appdirs 12 13from hat import aio 14from hat import json 15 16from hat.syslog.server import common 17from hat.syslog.server.backend import create_backend 18from hat.syslog.server.syslog import create_syslog_server 19from hat.syslog.server.ui import create_web_server 20 21 22mlog: logging.Logger = logging.getLogger('hat.syslog.server.main') 23"""Module logger""" 24 25package_path: Path = Path(__file__).parent 26"""Python package path""" 27 28user_data_dir: Path = Path(appdirs.user_data_dir('hat')) 29"""User data directory path""" 30 31user_conf_dir: Path = Path(appdirs.user_config_dir('hat')) 32"""User configuration directory path""" 33 34default_syslog_addr: str = 'tcp://0.0.0.0:6514' 35"""Default syslog listening address""" 36 37default_ui_addr: str = 'http://0.0.0.0:23020' 38"""Default UI listening address""" 39 40default_db_path: Path = user_data_dir / 'syslog.db' 41"""Default DB file path""" 42 43default_db_low_size: int = int(1e6) 44"""Default DB low size count""" 45 46default_db_high_size: int = int(1e7) 47"""Default DB high size count""" 48 49 50def create_argument_parser() -> argparse.ArgumentParser: 51 """Create argument parser""" 52 parser = argparse.ArgumentParser() 53 parser.add_argument( 54 '--conf', metavar='PATH', type=Path, 55 help="configuration defined by hat-syslog://server.yaml# " 56 "(default $XDG_CONFIG_HOME/hat/syslog.{yaml|yml|json})") 57 parser.add_argument( 58 '--log', metavar='LEVEL', type=str, 59 choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'], 60 help="console log level") 61 parser.add_argument( 62 '--syslog-addr', metavar='ADDR', type=str, 63 help=f"syslog listening address (default {default_syslog_addr})") 64 parser.add_argument( 65 '--syslog-pem', metavar='PATH', type=Path, 66 help="pem file path - mandatory for ssl communication") 67 parser.add_argument( 68 '--ui-addr', metavar='ADDR', type=str, 69 help=f"UI listening address (default {default_ui_addr})") 70 parser.add_argument( 71 '--db-path', metavar='PATH', type=Path, 72 help="sqlite database file path " 73 "(default $XDG_DATA_HOME/hat/syslog.db)") 74 parser.add_argument( 75 '--db-low-size', metavar='N', type=int, 76 help=f"number of messages kept in database after database " 77 f"cleanup (default {default_db_low_size})") 78 parser.add_argument( 79 '--db-high-size', metavar='N', type=int, 80 help=f"number of messages that will trigger database cleanup " 81 f"(default {default_db_high_size})") 82 parser.add_argument( 83 '--db-enable-archive', action='store_true', 84 help="should messages, deleted during database cleanup, be kept " 85 "in archive files") 86 parser.add_argument( 87 '--db-disable-journal', action='store_true', 88 help="disable sqlite jurnaling") 89 return parser 90 91 92def main(): 93 """Syslog Server""" 94 parser = create_argument_parser() 95 args = parser.parse_args() 96 97 conf_path = args.conf 98 if not conf_path: 99 for suffix in ('.yaml', '.yml', '.json'): 100 conf_path = (user_conf_dir / 'syslog').with_suffix(suffix) 101 if conf_path.exists(): 102 break 103 else: 104 conf_path = None 105 106 if conf_path == Path('-'): 107 conf = json.decode_stream(sys.stdin) 108 elif conf_path: 109 conf = json.decode_file(conf_path) 110 else: 111 conf = None 112 113 if conf: 114 common.json_schema_repo.validate('hat-syslog://server.yaml#', conf) 115 116 if args.log: 117 log_conf = _get_console_log_conf(args.log) 118 elif conf: 119 log_conf = conf['log'] 120 else: 121 log_conf = {'version': 1} 122 123 logging.config.dictConfig(log_conf) 124 125 syslog_addr = (args.syslog_addr if args.syslog_addr else 126 conf['syslog_addr'] if conf else 127 default_syslog_addr) 128 129 syslog_pem = (args.syslog_pem if args.syslog_pem else 130 Path(conf['syslog_pem']) if conf and 'syslog_pem' in conf else # NOQA 131 None) 132 133 ui_addr = (args.ui_addr if args.ui_addr else 134 conf['ui_addr'] if conf else 135 default_ui_addr) 136 137 db_path = (args.db_path if args.db_path else 138 Path(conf['db_path']) if conf else 139 default_db_path) 140 141 db_low_size = (args.db_low_size if args.db_low_size is not None else 142 conf['db_low_size'] if conf else 143 default_db_low_size) 144 145 db_high_size = (args.db_high_size if args.db_high_size is not None else 146 conf['db_high_size'] if conf else 147 default_db_high_size) 148 149 db_enable_archive = (True if args.db_enable_archive else 150 conf['db_enable_archive'] if conf else 151 False) 152 153 db_disable_journal = (True if args.db_disable_journal else 154 conf['db_disable_journal'] if conf else 155 False) 156 157 aio.init_asyncio() 158 with contextlib.suppress(asyncio.CancelledError): 159 aio.run_asyncio(async_main(syslog_addr=syslog_addr, 160 syslog_pem=syslog_pem, 161 ui_addr=ui_addr, 162 db_path=db_path, 163 db_low_size=db_low_size, 164 db_high_size=db_high_size, 165 db_enable_archive=db_enable_archive, 166 db_disable_journal=db_disable_journal)) 167 168 169async def async_main(syslog_addr: str, 170 syslog_pem: typing.Optional[Path], 171 ui_addr: str, 172 db_path: Path, 173 db_low_size: int, 174 db_high_size: int, 175 db_enable_archive: bool, 176 db_disable_journal: bool): 177 """Syslog Server async main""" 178 async_group = aio.Group() 179 180 async def async_close(): 181 await async_group.async_close() 182 await asyncio.sleep(0.1) 183 184 try: 185 mlog.debug("creating backend...") 186 backend = await _create_resource(async_group, create_backend, 187 db_path, db_low_size, db_high_size, 188 db_enable_archive, db_disable_journal) 189 190 mlog.debug("creating web server...") 191 await _create_resource(async_group, create_web_server, ui_addr, 192 backend) 193 194 mlog.debug("creating syslog server...") 195 await _create_resource(async_group, create_syslog_server, syslog_addr, 196 syslog_pem, backend) 197 198 mlog.debug("initialization done") 199 await async_group.wait_closing() 200 201 finally: 202 mlog.debug("closing...") 203 await aio.uncancellable(async_close()) 204 205 206def _get_console_log_conf(level): 207 return { 208 'version': 1, 209 'formatters': { 210 'syslog_server_console': { 211 'format': '[%(asctime)s %(levelname)s %(name)s] %(message)s'}}, 212 'handlers': { 213 'syslog_server_console': { 214 'class': 'logging.StreamHandler', 215 'formatter': 'syslog_server_console', 216 'level': level}}, 217 'loggers': { 218 'hat.syslog': { 219 'level': level}}, 220 'root': { 221 'level': 'INFO' if level == 'DEBUG' else level, 222 'handlers': ['syslog_server_console']}, 223 'disable_existing_loggers': False} 224 225 226async def _create_resource(async_group, fn, *args): 227 resource = await async_group.spawn(fn, *args) 228 async_group.spawn(aio.call_on_cancel, resource.async_close) 229 async_group.spawn(aio.call_on_done, resource.wait_closing(), 230 async_group.close) 231 return resource 232 233 234if __name__ == '__main__': 235 sys.argv[0] = 'hat-syslog' 236 sys.exit(main())
Module logger
package_path: pathlib.Path = PosixPath('/home/bozo/repos/hat/hat-syslog/src_py/hat/syslog/server')
Python package path
user_data_dir: pathlib.Path = PosixPath('/home/bozo/.local/share/hat')
User data directory path
user_conf_dir: pathlib.Path = PosixPath('/home/bozo/.config/hat')
User configuration directory path
default_syslog_addr: str = 'tcp://0.0.0.0:6514'
Default syslog listening address
default_ui_addr: str = 'http://0.0.0.0:23020'
Default UI listening address
default_db_path: pathlib.Path = PosixPath('/home/bozo/.local/share/hat/syslog.db')
Default DB file path
default_db_low_size: int = 1000000
Default DB low size count
default_db_high_size: int = 10000000
Default DB high size count
def
create_argument_parser() -> argparse.ArgumentParser:
51def create_argument_parser() -> argparse.ArgumentParser: 52 """Create argument parser""" 53 parser = argparse.ArgumentParser() 54 parser.add_argument( 55 '--conf', metavar='PATH', type=Path, 56 help="configuration defined by hat-syslog://server.yaml# " 57 "(default $XDG_CONFIG_HOME/hat/syslog.{yaml|yml|json})") 58 parser.add_argument( 59 '--log', metavar='LEVEL', type=str, 60 choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'], 61 help="console log level") 62 parser.add_argument( 63 '--syslog-addr', metavar='ADDR', type=str, 64 help=f"syslog listening address (default {default_syslog_addr})") 65 parser.add_argument( 66 '--syslog-pem', metavar='PATH', type=Path, 67 help="pem file path - mandatory for ssl communication") 68 parser.add_argument( 69 '--ui-addr', metavar='ADDR', type=str, 70 help=f"UI listening address (default {default_ui_addr})") 71 parser.add_argument( 72 '--db-path', metavar='PATH', type=Path, 73 help="sqlite database file path " 74 "(default $XDG_DATA_HOME/hat/syslog.db)") 75 parser.add_argument( 76 '--db-low-size', metavar='N', type=int, 77 help=f"number of messages kept in database after database " 78 f"cleanup (default {default_db_low_size})") 79 parser.add_argument( 80 '--db-high-size', metavar='N', type=int, 81 help=f"number of messages that will trigger database cleanup " 82 f"(default {default_db_high_size})") 83 parser.add_argument( 84 '--db-enable-archive', action='store_true', 85 help="should messages, deleted during database cleanup, be kept " 86 "in archive files") 87 parser.add_argument( 88 '--db-disable-journal', action='store_true', 89 help="disable sqlite jurnaling") 90 return parser
Create argument parser
def
main():
93def main(): 94 """Syslog Server""" 95 parser = create_argument_parser() 96 args = parser.parse_args() 97 98 conf_path = args.conf 99 if not conf_path: 100 for suffix in ('.yaml', '.yml', '.json'): 101 conf_path = (user_conf_dir / 'syslog').with_suffix(suffix) 102 if conf_path.exists(): 103 break 104 else: 105 conf_path = None 106 107 if conf_path == Path('-'): 108 conf = json.decode_stream(sys.stdin) 109 elif conf_path: 110 conf = json.decode_file(conf_path) 111 else: 112 conf = None 113 114 if conf: 115 common.json_schema_repo.validate('hat-syslog://server.yaml#', conf) 116 117 if args.log: 118 log_conf = _get_console_log_conf(args.log) 119 elif conf: 120 log_conf = conf['log'] 121 else: 122 log_conf = {'version': 1} 123 124 logging.config.dictConfig(log_conf) 125 126 syslog_addr = (args.syslog_addr if args.syslog_addr else 127 conf['syslog_addr'] if conf else 128 default_syslog_addr) 129 130 syslog_pem = (args.syslog_pem if args.syslog_pem else 131 Path(conf['syslog_pem']) if conf and 'syslog_pem' in conf else # NOQA 132 None) 133 134 ui_addr = (args.ui_addr if args.ui_addr else 135 conf['ui_addr'] if conf else 136 default_ui_addr) 137 138 db_path = (args.db_path if args.db_path else 139 Path(conf['db_path']) if conf else 140 default_db_path) 141 142 db_low_size = (args.db_low_size if args.db_low_size is not None else 143 conf['db_low_size'] if conf else 144 default_db_low_size) 145 146 db_high_size = (args.db_high_size if args.db_high_size is not None else 147 conf['db_high_size'] if conf else 148 default_db_high_size) 149 150 db_enable_archive = (True if args.db_enable_archive else 151 conf['db_enable_archive'] if conf else 152 False) 153 154 db_disable_journal = (True if args.db_disable_journal else 155 conf['db_disable_journal'] if conf else 156 False) 157 158 aio.init_asyncio() 159 with contextlib.suppress(asyncio.CancelledError): 160 aio.run_asyncio(async_main(syslog_addr=syslog_addr, 161 syslog_pem=syslog_pem, 162 ui_addr=ui_addr, 163 db_path=db_path, 164 db_low_size=db_low_size, 165 db_high_size=db_high_size, 166 db_enable_archive=db_enable_archive, 167 db_disable_journal=db_disable_journal))
Syslog Server
async def
async_main( syslog_addr: str, syslog_pem: Optional[pathlib.Path], ui_addr: str, db_path: pathlib.Path, db_low_size: int, db_high_size: int, db_enable_archive: bool, db_disable_journal: bool):
170async def async_main(syslog_addr: str, 171 syslog_pem: typing.Optional[Path], 172 ui_addr: str, 173 db_path: Path, 174 db_low_size: int, 175 db_high_size: int, 176 db_enable_archive: bool, 177 db_disable_journal: bool): 178 """Syslog Server async main""" 179 async_group = aio.Group() 180 181 async def async_close(): 182 await async_group.async_close() 183 await asyncio.sleep(0.1) 184 185 try: 186 mlog.debug("creating backend...") 187 backend = await _create_resource(async_group, create_backend, 188 db_path, db_low_size, db_high_size, 189 db_enable_archive, db_disable_journal) 190 191 mlog.debug("creating web server...") 192 await _create_resource(async_group, create_web_server, ui_addr, 193 backend) 194 195 mlog.debug("creating syslog server...") 196 await _create_resource(async_group, create_syslog_server, syslog_addr, 197 syslog_pem, backend) 198 199 mlog.debug("initialization done") 200 await async_group.wait_closing() 201 202 finally: 203 mlog.debug("closing...") 204 await aio.uncancellable(async_close())
Syslog Server async main