bw-essentials-core 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bw-essentials-core might be problematic. Click here for more details.

@@ -0,0 +1,173 @@
1
+ """
2
+ Module to store schemas for teams workflows.
3
+ """
4
+ from datetime import datetime
5
+
6
+
7
+ def get_error_schema(service_url, message, summary, error_trace=None, request_id=None):
8
+ """
9
+ Returns the schema for an error message to be sent to Microsoft Teams.
10
+
11
+ Args:
12
+ service_url (str): The URL of the service.
13
+ message (str): The error message.
14
+ summary (str): A summary of the error.
15
+ error_trace (str, optional): The error trace details. Defaults to None.
16
+ request_id (str, optional): The ID of the request. Defaults to None.
17
+
18
+ Returns:
19
+ dict: The schema for the error message.
20
+ """
21
+ return {
22
+ "type": "message",
23
+ "attachments": [
24
+ {
25
+ "contentType": "application/vnd.microsoft.card.adaptive",
26
+ "content": {
27
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
28
+ "type": "AdaptiveCard",
29
+ "version": "1.0",
30
+ "body": [
31
+ {
32
+ "type": "Container",
33
+ "items": [
34
+ {
35
+ "type": "TextBlock",
36
+ "text": "ERROR",
37
+ "color": "attention",
38
+ "weight": "bolder",
39
+ "size": "large"
40
+ }
41
+ ],
42
+ "style": "attention"
43
+ },
44
+ {
45
+ "type": "TextBlock",
46
+ "text": f"Service: {service_url}",
47
+ "weight": "bolder",
48
+ "wrap": True
49
+ },
50
+ {
51
+ "type": "TextBlock",
52
+ "text": f"{message}",
53
+ "weight": "bolder",
54
+ "wrap": True,
55
+ "isSubtle": True
56
+ },
57
+ {
58
+ "type": "TextBlock",
59
+ "text": "Summary:",
60
+ "weight": "bolder",
61
+ "wrap": True
62
+ },
63
+ {
64
+ "type": "TextBlock",
65
+ "text": f"{summary}",
66
+ "wrap": True,
67
+ "fontType": "monospace"
68
+ },
69
+ {
70
+ "type": "TextBlock",
71
+ "text": "Error Trace:",
72
+ "weight": "bolder",
73
+ "wrap": True
74
+ },
75
+ {
76
+ "type": "TextBlock",
77
+ "text": f"{error_trace}",
78
+ "wrap": True
79
+ },
80
+ {
81
+ "type": "TextBlock",
82
+ "text": "Request ID:",
83
+ "weight": "bolder",
84
+ "wrap": True
85
+ },
86
+ {
87
+ "type": "TextBlock",
88
+ "text": f"{request_id}",
89
+ "wrap": True
90
+ },
91
+ {
92
+ "type": "TextBlock",
93
+ "text": "Timestamp:",
94
+ "weight": "bolder",
95
+ "wrap": True
96
+ },
97
+ {
98
+ "type": "TextBlock",
99
+ "text": f"{str(datetime.now())}",
100
+ "wrap": True,
101
+ "isSubtle": True
102
+ }
103
+ ]
104
+ }
105
+ }
106
+ ]
107
+ }
108
+
109
+
110
+ def get_notification_schema(service_url, message):
111
+ """
112
+ Returns the schema for a message notification to be sent to Microsoft Teams.
113
+
114
+ Args:
115
+ service_url (str): The URL of the service.
116
+ message (str): The log message.
117
+
118
+ Returns:
119
+ dict: The schema for the log message.
120
+ """
121
+ return {
122
+ "type": "message",
123
+ "attachments": [
124
+ {
125
+ "contentType": "application/vnd.microsoft.card.adaptive",
126
+ "content": {
127
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
128
+ "type": "AdaptiveCard",
129
+ "version": "1.0",
130
+ "body": [
131
+ {
132
+ "type": "Container",
133
+ "items": [
134
+ {
135
+ "type": "TextBlock",
136
+ "text": "Notification",
137
+ "color": "good",
138
+ "weight": "bolder",
139
+ "size": "large"
140
+ }
141
+ ],
142
+ "style": "good"
143
+ },
144
+ {
145
+ "type": "TextBlock",
146
+ "text": f"Service: {service_url}",
147
+ "weight": "bolder",
148
+ "wrap": True
149
+ },
150
+ {
151
+ "type": "TextBlock",
152
+ "text": f"{message}",
153
+ "weight": "bolder",
154
+ "wrap": True,
155
+ "isSubtle": True
156
+ },
157
+ {
158
+ "type": "TextBlock",
159
+ "text": "Timestamp:",
160
+ "weight": "bolder",
161
+ "wrap": True
162
+ },
163
+ {
164
+ "type": "TextBlock",
165
+ "text": f"{str(datetime.now())}",
166
+ "wrap": True,
167
+ "isSubtle": True
168
+ }
169
+ ]
170
+ }
171
+ }
172
+ ]
173
+ }
@@ -0,0 +1,189 @@
1
+ """
2
+ notifications.py
3
+
4
+ This module provides a `Notifications` class for sending structured messages and alerts
5
+ to external communication tools such as Microsoft Teams and Zenduty. It is used to
6
+ inform stakeholders or developers about system events, including errors and general logs.
7
+ """
8
+
9
+ import json
10
+ import logging
11
+ import os
12
+ import sys
13
+ from importlib.util import spec_from_file_location, module_from_spec
14
+
15
+ import requests
16
+
17
+ from bw_essentials.notifications.teams_notification_schemas import get_notification_schema, get_error_schema
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class Notifications:
23
+ """
24
+ Notification module to send alerts and warnings via Microsoft Teams and Zenduty.
25
+
26
+ Args:
27
+ title (str): The title or service name triggering the notification.
28
+ summary (str, optional): A brief summary of the message or error.
29
+ message (str, optional): The main body of the message.
30
+ alert (bool, optional): If True, it's treated as an error; otherwise as a log. Defaults to False.
31
+ trace (str, optional): Optional traceback or detailed error string.
32
+ request_id (str, optional): Optional correlation ID for tracing logs.
33
+ """
34
+
35
+ def __init__(self,
36
+ title,
37
+ summary=None,
38
+ message=None,
39
+ alert=False,
40
+ trace=None,
41
+ request_id=None):
42
+ self.message = message
43
+ self.title = title
44
+ self.summary = summary
45
+ self.alert = alert
46
+ self.trace = trace
47
+ self.request_id = request_id
48
+ self.notify_on_teams = self._get_env_var("NOTIFY_ON_TEAMS")
49
+ self.notify_on_calls = self._get_env_var("NOTIFY_ON_CALLS")
50
+ self.webhook_url = self._get_env_var("TEAMS_WEBHOOK_URL")
51
+ self.zenduty_url = self._get_env_var("ZENDUTY_URL")
52
+ self.api_timeout = self._get_env_var("API_TIMEOUT")
53
+
54
+ def _get_env_var(self, key: str) -> str:
55
+ """
56
+ Fetch a required variable from bw_config.py located in the root directory.
57
+
58
+ Raises:
59
+ FileNotFoundError: If bw_config.py is not found.
60
+ AttributeError: If the requested key is not defined in the config.
61
+
62
+ Returns:
63
+ str: The value of the config variable.
64
+ """
65
+ config_path = os.path.join(os.getcwd(), "bw_config.py")
66
+
67
+ if not os.path.exists(config_path):
68
+ raise FileNotFoundError("`bw_config.py` file not found in the root directory. "
69
+ "Please ensure the config file exists.")
70
+
71
+ spec = spec_from_file_location("bw_config", config_path)
72
+ bw_config = module_from_spec(spec)
73
+ sys.modules["bw_config"] = bw_config
74
+ spec.loader.exec_module(bw_config)
75
+
76
+ if not hasattr(bw_config, key):
77
+ raise AttributeError(f"`{key}` not found in bw_config.py. Please define it in the config.")
78
+
79
+ return getattr(bw_config, key)
80
+
81
+ def __notify_teams_workflow(self):
82
+ """
83
+ Sends a notification to Microsoft Teams using Adaptive Cards.
84
+
85
+ Uses either the error schema or the log schema based on whether the notification
86
+ is an alert or not. This function posts the generated card payload to the configured
87
+ Teams webhook URL.
88
+
89
+ Returns:
90
+ None
91
+ """
92
+ logger.info("In __notify_teams_workflow")
93
+ try:
94
+ if self.notify_on_teams:
95
+ workflow_schema = get_notification_schema(self.title, self.message)
96
+ if self.alert:
97
+ workflow_schema = get_error_schema(
98
+ service_url=self.title,
99
+ message=self.message,
100
+ summary=self.summary,
101
+ error_trace=self.trace,
102
+ request_id=self.request_id
103
+ )
104
+
105
+ headers = {'Content-Type': 'application/json'}
106
+ response = requests.post(
107
+ self.webhook_url,
108
+ data=json.dumps(workflow_schema),
109
+ headers=headers
110
+ )
111
+ logger.info(f"{response =}")
112
+ else:
113
+ logger.info(f"Notification for teams is {self.notify_on_teams}. Message: {self.message}")
114
+ except Exception as exc:
115
+ logger.info("Error while notifying error to teams.")
116
+ logger.exception(exc)
117
+
118
+ def __notify_zenduty(self):
119
+ """
120
+ Sends a critical alert to Zenduty via its API endpoint.
121
+
122
+ Posts a payload including alert type, message, and summary. Primarily used for error alerts.
123
+
124
+ Returns:
125
+ None
126
+ """
127
+ if self.notify_on_calls:
128
+ payload = {
129
+ "alert_type": "critical",
130
+ "message": self.message,
131
+ "summary": self.summary
132
+ }
133
+ payload_json = json.dumps(payload)
134
+ response = requests.post(
135
+ self.zenduty_url,
136
+ data=payload_json,
137
+ timeout=float(self.api_timeout)
138
+ )
139
+ logger.info(response)
140
+ logger.info("Response from Zenduty Call API: An incident has been created")
141
+
142
+ def notify_message(self, message=None, summary=None, alert=False):
143
+ """
144
+ Sends a general log or information notification.
145
+
146
+ Args:
147
+ message (str, optional): The content of the message. Overrides initial message if provided.
148
+ summary (str, optional): Optional summary for the message.
149
+ alert (bool, optional): If True, message is sent as an alert.
150
+
151
+ Returns:
152
+ None
153
+ """
154
+ try:
155
+ self.alert = alert
156
+ if message:
157
+ self.message = message
158
+ if summary:
159
+ self.summary = summary
160
+ self.__notify_teams_workflow()
161
+ except Exception as exc:
162
+ logger.info("Error while notifying message to teams")
163
+ logger.exception(exc)
164
+
165
+ def notify_error(self, message=None, summary=None, alert=True, trace=None, request_id=None):
166
+ """
167
+ Sends an error notification to Microsoft Teams and Zenduty.
168
+
169
+ Args:
170
+ message (str, optional): Error message to be sent.
171
+ summary (str, optional): Summary or context for the error.
172
+ alert (bool, optional): Flag to indicate it's an error. Defaults to True.
173
+ trace (str, optional): Detailed traceback or stack trace of the error.
174
+ request_id (str, optional): Optional request ID for tracking.
175
+
176
+ Returns:
177
+ None
178
+ """
179
+ self.alert = alert
180
+ if summary:
181
+ self.summary = summary
182
+ if message:
183
+ self.message = message
184
+ if trace:
185
+ self.trace = trace
186
+ if request_id:
187
+ self.request_id = request_id
188
+ self.__notify_zenduty()
189
+ self.__notify_teams_workflow()
File without changes