Skip to content

Commit 6c82e2d

Browse files
committed
Merge branch 'main' into feat-docstrings
2 parents 5296415 + d63a6a8 commit 6c82e2d

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed

__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from smartinspect import SmartInspect # noqa
2+
from smartinspect_handler.smartinspect_handler import SmartInspectHandler # noqa
3+
from connections.builders import ConnectionStringBuilder # noqa

smartinspect_handler/__init__.py

Whitespace-only changes.
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import logging
2+
import typing
3+
4+
from session.session import Session
5+
from smartinspect import SmartInspect
6+
7+
8+
# noinspection PyBroadException
9+
class SmartInspectHandler(logging.Handler):
10+
"""
11+
A custom logging Handler which is designed to be used with Python logging module,
12+
This handler sends log messages to SmartInspect defined destination.
13+
14+
Usage example:
15+
-------
16+
| # create a logging logger
17+
| logger = logging.getLogger(__name__)
18+
19+
| # create a connection string using ConnectionStringBuilder
20+
| conn_string = ConnectionStringBuilder().add_tcp_protocol().set_host("127.0.0.1").set_port(4228).set_timeout(
21+
30000).set_async_enabled(True).end_protocol().build()
22+
23+
| # create a SmartInspectHandler instance, set format and attach handler to the logger
24+
| handler = SmartInspectHandler("Client app", conn_string)
25+
| handler.setFormatter(logging.Formatter("%(threadName)s, %(asctime)s: %(module)s @ %(funcName)s: %(message)s"))
26+
| logger.addHandler(handler)
27+
| logger.setLevel(logging.DEBUG)
28+
29+
| # log as you usually log with logging logger
30+
| logger.info("Message")
31+
| # explicitly dispose of handler when finished working in async mode
32+
| handler.dispose()
33+
34+
"""
35+
36+
def __init__(self, app_name: str, conn_string: str):
37+
"""
38+
Initializes an instance of SmartinspectHandler.
39+
40+
:param app_name: The name of the application
41+
:param conn_string: A SmartInspect connection string.
42+
"""
43+
44+
logging.Handler.__init__(self)
45+
46+
self._si: typing.Optional[SmartInspect] = None
47+
self._si_session: typing.Optional[Session] = None
48+
self._si_connection_string: str = conn_string
49+
self._app_name: str = app_name
50+
51+
def get_si(self) -> SmartInspect:
52+
"""
53+
This method gets underlying SmartInspect instance.
54+
This will enable SmartInspect if it has not been enabled yet.
55+
By using the underlying SmartInspect instance you can use both logging logger and SI directly.
56+
57+
Usage example:
58+
-------
59+
60+
| # create a logging logger
61+
| logger = logging.getLogger(__name__)
62+
63+
| # create a connection string using ConnectionStringBuilder
64+
| conn_string = ConnectionStringBuilder().add_tcp_protocol().set_host("127.0.0.1").set_port(4228).
65+
set_timeout(30000).set_async_enabled(False).end_protocol().build()
66+
67+
| # create a SmartInspectHandler instance, set format and attach handler to the logger
68+
| handler = SmartInspectHandler("Client app", conn_string)
69+
| handler.setFormatter(logging.Formatter("%(asctime)s: %(module)s @ %(funcName)s: %(message)s"))
70+
| logger.addHandler(handler)
71+
| logger.setLevel(logging.DEBUG)
72+
73+
| # log from si
74+
| si = handler.get_si()
75+
| session = si.add_session("Session", True)
76+
| session.log_message("Logging from SI")
77+
78+
| # log from logging logger
79+
| logger.info("Hello from logging")
80+
81+
| # and again from si
82+
| session.log_message("Another message from SI")
83+
"""
84+
self._enable_si()
85+
return self._si
86+
87+
def emit(self, record: logging.LogRecord) -> None:
88+
"""
89+
Emit a record.
90+
91+
If SmartInspect Session has not been initialized yet, it is created.
92+
93+
If a formatter is specified, it is used to format the record.
94+
The record is then written to destination as defined by SmartInspect session.
95+
"""
96+
try:
97+
self._enable_si()
98+
self._create_si_session()
99+
self._do_emit(record)
100+
except Exception:
101+
self.handleError(record)
102+
103+
def _enable_si(self) -> None:
104+
"""
105+
Enable SmartInspect instance using connection string and app_name provided
106+
during SmartInspect Handler initialization.
107+
"""
108+
if not self._si or not self._si.is_enabled:
109+
try:
110+
self._si = SmartInspect(self._app_name)
111+
self._si.set_connections(self._si_connection_string)
112+
self._si.set_enabled(True)
113+
except Exception as e:
114+
raise e
115+
116+
def _create_si_session(self) -> None:
117+
"""
118+
Create SmartInspect Session used to dispatch logging Records.
119+
A Session is only created if it does not exist already.
120+
"""
121+
if not self._si_session:
122+
self._si_session = self._si.add_session("Session", True)
123+
124+
def _do_emit(self, record: logging.LogRecord) -> None:
125+
"""
126+
Emit logging Records to SmartInspect destination protocol according to logging Level.
127+
"""
128+
129+
try:
130+
msg = self.format(record)
131+
132+
if record.levelno <= logging.DEBUG:
133+
self._si_session.log_debug(msg)
134+
elif record.levelno <= logging.INFO:
135+
self._si_session.log_message(msg)
136+
elif record.levelno <= logging.WARNING:
137+
self._si_session.log_warning(msg)
138+
elif record.levelno <= logging.ERROR:
139+
self._si_session.log_error(msg)
140+
else:
141+
self._si_session.log_fatal(msg)
142+
143+
except Exception:
144+
self.handleError(record)
145+
146+
def dispose(self) -> None:
147+
"""
148+
Disposes of the underlying SmartInspect instance.
149+
When running in asynchronous mode, SmartInspect starts additional threads to make async mode work.
150+
.dispose() method needs to be explicitly called to release all the resources associated with SmartInspect
151+
when logging is finished.
152+
153+
Usage example:
154+
-------
155+
| # create a logging logger
156+
| logger = logging.getLogger(__name__)
157+
158+
| # create a connection string using ConnectionStringBuilder
159+
| conn_string = ConnectionStringBuilder().add_tcp_protocol().set_host("127.0.0.1").set_port(4228).set_timeout(
160+
30000).set_async_enabled(True).end_protocol().build()
161+
162+
| # create a SmartInspectHandler instance, set format and attach handler to the logger
163+
| handler = SmartInspectHandler("Client app", conn_string)
164+
| handler.setFormatter(logging.Formatter("%(asctime)s: %(module)s @ %(funcName)s: %(message)s"))
165+
| logger.addHandler(handler)
166+
| logger.setLevel(logging.DEBUG)
167+
168+
| # log as you usually log with logging logger
169+
| logger.info("Message")
170+
| # explicitly dispose of handler when finished working in async mode
171+
| handler.dispose()
172+
"""
173+
if self._si:
174+
self._si.dispose()

0 commit comments

Comments
 (0)