Skip to content

Commit 6bf4734

Browse files
authored
chore: merge main into develop (#367)
marge main to develop
2 parents 525eafa + 2952714 commit 6bf4734

File tree

8 files changed

+181
-32
lines changed

8 files changed

+181
-32
lines changed

.github/workflows/build-test-release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
steps:
1919
- uses: actions/checkout@v4
2020
- id: matrix
21-
uses: splunk/addonfactory-test-matrix-action@v1
21+
uses: splunk/addonfactory-test-matrix-action@v2
2222

2323
fossa-scan:
2424
continue-on-error: true
@@ -47,7 +47,7 @@ jobs:
4747
runs-on: ubuntu-latest
4848
steps:
4949
- uses: actions/checkout@v4
50-
- uses: apache/skywalking-eyes@v0.5.0
50+
- uses: apache/skywalking-eyes@v0.6.0
5151

5252
pre-commit:
5353
runs-on: ubuntu-latest

poetry.lock

Lines changed: 31 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
[tool.poetry]
1818
name = "solnlib"
19-
version = "4.13.0-beta.2"
19+
version = "4.14.1"
2020
description = "The Splunk Software Development Kit for Splunk Solutions"
2121
authors = ["Splunk <addonfactory@splunk.com>"]
2222
license = "Apache-2.0"

solnlib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,4 @@
5454
"utils",
5555
]
5656

57-
__version__ = "4.13.0-beta.2"
57+
__version__ = "4.14.1"

solnlib/conf_manager.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ def get_log_level(
506506
session_key: str,
507507
app_name: str,
508508
conf_name: str,
509+
log_stanza: str = "logging",
509510
log_level_field: str = "loglevel",
510511
default_log_level: str = "INFO",
511512
) -> str:
@@ -517,6 +518,7 @@ def get_log_level(
517518
session_key: Splunk access token.
518519
app_name: Add-on name.
519520
conf_name: Configuration file name where logging stanza is.
521+
log_stanza: Logging stanza to define `log_level_field` and its value.
520522
log_level_field: Logging level field name under logging stanza.
521523
default_log_level: Default log level to return in case of errors.
522524
@@ -547,7 +549,7 @@ def get_log_level(
547549
)
548550
return default_log_level
549551
try:
550-
logging_details = conf.get("logging")
552+
logging_details = conf.get(log_stanza)
551553
return logging_details.get(log_level_field, default_log_level)
552554
except ConfStanzaNotExistException:
553555
logger.error(

solnlib/log.py

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -252,18 +252,52 @@ def modular_input_end(logger: logging.Logger, modular_input_name: str):
252252

253253

254254
def events_ingested(
255-
logger: logging.Logger, modular_input_name: str, sourcetype: str, n_events: int
255+
logger: logging.Logger,
256+
modular_input_name: str,
257+
sourcetype: str,
258+
n_events: int,
259+
index: str,
260+
account: str = None,
261+
host: str = None,
256262
):
257-
"""Specific function to log the number of events ingested."""
258-
log_event(
259-
logger,
260-
{
261-
"action": "events_ingested",
262-
"modular_input_name": modular_input_name,
263-
"sourcetype_ingested": sourcetype,
264-
"n_events": n_events,
265-
},
266-
)
263+
"""Specific function to log the basic information of events ingested for
264+
the monitoring dashboard.
265+
266+
Arguments:
267+
logger: Add-on logger.
268+
modular_input_name: Full name of the modular input. It needs to be in a format <input_type>://<input_name>.
269+
In case of invalid format ValueError is raised.
270+
sourcetype: Source type used to write event.
271+
n_events: Number of ingested events.
272+
index: Index used to write event.
273+
account: Account used to write event. (optional)
274+
host: Host used to write event. (optional)
275+
"""
276+
277+
if "://" in modular_input_name:
278+
input_name = modular_input_name.split("/")[-1]
279+
else:
280+
raise ValueError(
281+
f"Invalid modular input name: {modular_input_name}. "
282+
f"It should be in format <input_type>://<input_name>"
283+
)
284+
285+
result = {
286+
"action": "events_ingested",
287+
"modular_input_name": modular_input_name,
288+
"sourcetype_ingested": sourcetype,
289+
"n_events": n_events,
290+
"event_input": input_name,
291+
"event_index": index,
292+
}
293+
294+
if account:
295+
result["event_account"] = account
296+
297+
if host:
298+
result["event_host"] = host
299+
300+
log_event(logger, result)
267301

268302

269303
def log_exception(

tests/unit/test_conf_manager.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,60 @@ def test_get_log_level_when_error_getting_conf(mock_conf_manager_class):
3232
)
3333

3434
assert expected_log_level == log_level
35+
36+
37+
@mock.patch.object(conf_manager, "ConfManager")
38+
def test_get_log_level_with_custom_values(mock_conf_manager_class):
39+
mock_conf_manager = mock_conf_manager_class.return_value
40+
mock_conf_manager.get_conf.return_value = {"my_logger": {"my_field": "DEBUG"}}
41+
expected_log_level = "DEBUG"
42+
43+
log_level = conf_manager.get_log_level(
44+
logger=mock.MagicMock(),
45+
session_key="session_key",
46+
app_name="app_name",
47+
conf_name="conf_name",
48+
log_stanza="my_logger",
49+
log_level_field="my_field",
50+
)
51+
52+
assert log_level == expected_log_level
53+
54+
55+
@mock.patch.object(conf_manager, "ConfManager")
56+
def test_get_log_level_with_no_logging_stanza(mock_conf_manager_class):
57+
mock_conf_manager = mock_conf_manager_class.return_value
58+
mock_conf_manager.get_conf.return_value = mock.MagicMock()
59+
mock_conf_manager.get_conf.return_value.get.side_effect = (
60+
conf_manager.ConfStanzaNotExistException
61+
)
62+
logger = mock.MagicMock()
63+
expected_log_level = "INFO"
64+
65+
log_level = conf_manager.get_log_level(
66+
logger=logger,
67+
session_key="session_key",
68+
app_name="app_name",
69+
conf_name="conf_name",
70+
log_stanza="my_logger",
71+
log_level_field="my_field",
72+
)
73+
74+
assert log_level == expected_log_level
75+
assert logger.error.call_count == 1
76+
77+
78+
@mock.patch.object(conf_manager, "ConfManager")
79+
def test_get_log_level_with_default_fields(mock_conf_manager_class):
80+
mock_conf_manager = mock_conf_manager_class.return_value
81+
mock_conf_manager.get_conf.return_value = {"logging": {"loglevel": "WARN"}}
82+
expected_log_level = "WARN"
83+
84+
log_level = conf_manager.get_log_level(
85+
logger=mock.MagicMock(),
86+
session_key="session_key",
87+
app_name="app_name",
88+
conf_name="conf_name",
89+
)
90+
91+
assert log_level == expected_log_level

tests/unit/test_log.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import threading
2323
import traceback
2424
import time
25+
import pytest
2526
from unittest import mock
2627

2728
from solnlib import log
@@ -193,14 +194,52 @@ def test_modular_input_end():
193194

194195
def test_events_ingested():
195196
with mock.patch("logging.Logger") as mock_logger:
196-
log.events_ingested(mock_logger, "modular_input_name", "sourcetype", 5)
197+
log.events_ingested(
198+
mock_logger, "input_type://input_name", "sourcetype", 5, "default"
199+
)
200+
201+
mock_logger.log.assert_called_once_with(
202+
logging.INFO,
203+
"action=events_ingested modular_input_name=input_type://input_name sourcetype_ingested=sourcetype "
204+
"n_events=5 event_input=input_name event_index=default",
205+
)
206+
207+
with mock.patch("logging.Logger") as mock_logger:
208+
log.events_ingested(
209+
mock_logger,
210+
"demo://modular_input_name",
211+
"sourcetype",
212+
5,
213+
"default",
214+
host="abcd",
215+
account="test_acc",
216+
)
197217

198218
mock_logger.log.assert_called_once_with(
199219
logging.INFO,
200-
"action=events_ingested modular_input_name=modular_input_name sourcetype_ingested=sourcetype n_events=5",
220+
"action=events_ingested modular_input_name=demo://modular_input_name sourcetype_ingested=sourcetype n_"
221+
"events=5 event_input=modular_input_name event_index=default event_account=test_acc event_host=abcd",
201222
)
202223

203224

225+
def test_events_ingested_invalid_input():
226+
exp_msg = "Invalid modular input name: modular_input_name. It should be in format <input_type>://<input_name>"
227+
228+
with pytest.raises(ValueError) as excinfo:
229+
with mock.patch("logging.Logger") as mock_logger:
230+
log.events_ingested(
231+
mock_logger,
232+
"modular_input_name",
233+
"sourcetype",
234+
5,
235+
"default",
236+
host="abcd",
237+
account="test_acc",
238+
)
239+
240+
assert exp_msg == str(excinfo.value)
241+
242+
204243
def test_log_exceptions_full_msg():
205244
start_msg = "some msg before exception"
206245
with mock.patch("logging.Logger") as mock_logger:

0 commit comments

Comments
 (0)