summaryrefslogtreecommitdiff
path: root/ncserver
diff options
context:
space:
mode:
Diffstat (limited to 'ncserver')
-rw-r--r--ncserver/base/log.py70
-rw-r--r--ncserver/base/util.py5
-rw-r--r--ncserver/server.py20
3 files changed, 93 insertions, 2 deletions
diff --git a/ncserver/base/log.py b/ncserver/base/log.py
new file mode 100644
index 0000000..053baec
--- /dev/null
+++ b/ncserver/base/log.py
@@ -0,0 +1,70 @@
+"""
+NETCONF for APK Distributions server:
+ Logging setup and routines.
+
+Copyright © 2020 Adélie Software in the Public Benefit, Inc.
+
+Released under the terms of the NCSA license. See the LICENSE file included
+with this source distribution for more information.
+
+SPDX-License-Identifier: NCSA
+"""
+
+
+import logging
+
+from socket import gethostname
+from taillight import Signal
+
+
+HOSTNAME_CHANGED = Signal(('node_changed', 'sys:hostname'))
+"""The signal that will fire when the hostname is changed."""
+
+HANDLER = logging.StreamHandler()
+"""The root log handler."""
+
+LOG_AUTH = logging.getLogger('ncserver.auth')
+"""The authentication logger."""
+
+LOG_CONFIG = logging.getLogger('ncserver.config')
+"""The configuration logger."""
+
+LOG_OPERATIONAL = logging.getLogger('ncserver.operational')
+"""The operational logger."""
+
+
+def configure_format(hostname: str):
+ """Configure the formatter for the root log handler."""
+ fmt = logging.Formatter('%(asctime)s ' + hostname +
+ ' %(name)s %(levelname)s: %(message)s',
+ '%Y-%m-%dT%H:%M:%S')
+ HANDLER.setFormatter(fmt)
+
+
+def configure_logging(level: int):
+ """Configure the logging system."""
+ configure_format(gethostname())
+
+ root = logging.getLogger()
+
+ HANDLER.setLevel(level)
+ root.setLevel(level)
+
+ root.addHandler(HANDLER)
+
+
+
+HOSTNAME_CHANGED.add(configure_format)
+
+if not hasattr(logging, 'NOTICE'):
+ logging.addLevelName(25, 'NOTICE')
+ logging.NOTICE = 25
+
+ def log_notice(self, message, *args, **kwargs):
+ if self.isEnabledFor(25):
+ self._log(25, message, args, **kwargs)
+ logging.getLoggerClass().notice = log_notice
+
+ def root_notice(message, *args, **kwargs):
+ logging.log(25, message, *args, **kwargs)
+ logging.notice = root_notice
diff --git a/ncserver/base/util.py b/ncserver/base/util.py
index 5df4704..164e309 100644
--- a/ncserver/base/util.py
+++ b/ncserver/base/util.py
@@ -22,6 +22,11 @@ def _(the_string: str) -> str:
return the_string
+def user_for_session(session) -> str:
+ """Determine the user for the specified session."""
+ return session.pkt_stream.stream.get_transport().get_username()
+
+
def ensure_leaf(rpc, node):
"""Ensure that the node is a leaf (contains no child nodes)."""
if len(node) > 0:
diff --git a/ncserver/server.py b/ncserver/server.py
index 0c56c2a..dd35b2d 100644
--- a/ncserver/server.py
+++ b/ncserver/server.py
@@ -17,13 +17,22 @@ from lxml import etree
from netconf import error, util
from netconf.server import NetconfSSHServer, SSHAuthorizedKeysController
+from ncserver.base.log import configure_logging, LOG_CONFIG
from ncserver.base.modman import ModuleManager
+from ncserver.base.util import user_for_session
from ncserver.config import ConfigManager
QName = etree.QName # pylint: disable=I1101
+def log_read(session, rpc):
+ """Log a configuration read."""
+ LOG_CONFIG.debug('%s on session %d is requesting configuration: %s',
+ user_for_session(session), session.session_id, etree.tostring(rpc)
+ )
+
+
class Server:
"""The NETCONF server component."""
@@ -40,9 +49,14 @@ class Server:
self.debug = self.config.get('server', 'debug')
if self.debug:
- logging.basicConfig(level=logging.DEBUG)
+ configure_logging(logging.DEBUG)
else:
- logging.basicConfig(level=logging.INFO)
+ loglevel = 'notice'
+ try:
+ loglevel = self.config.get('server', 'loglevel')
+ except KeyError:
+ pass
+ configure_logging(getattr(logging, loglevel.upper()))
self.server = NetconfSSHServer(
self.auth, self, port, self.config.get('server', 'host_key'),
@@ -71,6 +85,7 @@ class Server:
def rpc_get(self, session, rpc, filter_or_none): # pylint: disable=W0613
"""Handle the <get/> RPC."""
+ log_read(session, rpc)
root = util.elm('nc:data')
self.modman.collect_running(root)
self.modman.collect_operational(root)
@@ -80,6 +95,7 @@ class Server:
# pylint: disable=W0613
def rpc_get_config(self, session, rpc, source, filter_or_none):
"""Handle the <get-config/> RPC."""
+ log_read(session, rpc)
root = util.elm('nc:data')
self.modman.collect_running(root)