Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: merge main into develop #367

Merged
merged 12 commits into from
Jun 10, 2024
Merged
4 changes: 2 additions & 2 deletions .github/workflows/build-test-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- id: matrix
uses: splunk/addonfactory-test-matrix-action@v1
uses: splunk/addonfactory-test-matrix-action@v2

fossa-scan:
continue-on-error: true
Expand Down Expand Up @@ -47,7 +47,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: apache/skywalking-eyes@v0.5.0
- uses: apache/skywalking-eyes@v0.6.0

pre-commit:
runs-on: ubuntu-latest
Expand Down
45 changes: 31 additions & 14 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

[tool.poetry]
name = "solnlib"
version = "4.13.0-beta.2"
version = "4.14.1"
description = "The Splunk Software Development Kit for Splunk Solutions"
authors = ["Splunk <[email protected]>"]
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion solnlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@
"utils",
]

__version__ = "4.13.0-beta.2"
__version__ = "4.14.1"
4 changes: 3 additions & 1 deletion solnlib/conf_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ def get_log_level(
session_key: str,
app_name: str,
conf_name: str,
log_stanza: str = "logging",
log_level_field: str = "loglevel",
default_log_level: str = "INFO",
) -> str:
Expand All @@ -517,6 +518,7 @@ def get_log_level(
session_key: Splunk access token.
app_name: Add-on name.
conf_name: Configuration file name where logging stanza is.
log_stanza: Logging stanza to define `log_level_field` and its value.
log_level_field: Logging level field name under logging stanza.
default_log_level: Default log level to return in case of errors.

Expand Down Expand Up @@ -547,7 +549,7 @@ def get_log_level(
)
return default_log_level
try:
logging_details = conf.get("logging")
logging_details = conf.get(log_stanza)
return logging_details.get(log_level_field, default_log_level)
except ConfStanzaNotExistException:
logger.error(
Expand Down
56 changes: 45 additions & 11 deletions solnlib/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,18 +252,52 @@ def modular_input_end(logger: logging.Logger, modular_input_name: str):


def events_ingested(
logger: logging.Logger, modular_input_name: str, sourcetype: str, n_events: int
logger: logging.Logger,
modular_input_name: str,
sourcetype: str,
n_events: int,
index: str,
account: str = None,
host: str = None,
):
"""Specific function to log the number of events ingested."""
log_event(
logger,
{
"action": "events_ingested",
"modular_input_name": modular_input_name,
"sourcetype_ingested": sourcetype,
"n_events": n_events,
},
)
"""Specific function to log the basic information of events ingested for
the monitoring dashboard.

Arguments:
logger: Add-on logger.
modular_input_name: Full name of the modular input. It needs to be in a format <input_type>://<input_name>.
In case of invalid format ValueError is raised.
sourcetype: Source type used to write event.
n_events: Number of ingested events.
index: Index used to write event.
account: Account used to write event. (optional)
host: Host used to write event. (optional)
"""

if "://" in modular_input_name:
input_name = modular_input_name.split("/")[-1]
else:
raise ValueError(
f"Invalid modular input name: {modular_input_name}. "
f"It should be in format <input_type>://<input_name>"
)

result = {
"action": "events_ingested",
"modular_input_name": modular_input_name,
"sourcetype_ingested": sourcetype,
"n_events": n_events,
"event_input": input_name,
"event_index": index,
}

if account:
result["event_account"] = account

if host:
result["event_host"] = host

log_event(logger, result)


def log_exception(
Expand Down
57 changes: 57 additions & 0 deletions tests/unit/test_conf_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,60 @@ def test_get_log_level_when_error_getting_conf(mock_conf_manager_class):
)

assert expected_log_level == log_level


@mock.patch.object(conf_manager, "ConfManager")
def test_get_log_level_with_custom_values(mock_conf_manager_class):
mock_conf_manager = mock_conf_manager_class.return_value
mock_conf_manager.get_conf.return_value = {"my_logger": {"my_field": "DEBUG"}}
expected_log_level = "DEBUG"

log_level = conf_manager.get_log_level(
logger=mock.MagicMock(),
session_key="session_key",
app_name="app_name",
conf_name="conf_name",
log_stanza="my_logger",
log_level_field="my_field",
)

assert log_level == expected_log_level


@mock.patch.object(conf_manager, "ConfManager")
def test_get_log_level_with_no_logging_stanza(mock_conf_manager_class):
mock_conf_manager = mock_conf_manager_class.return_value
mock_conf_manager.get_conf.return_value = mock.MagicMock()
mock_conf_manager.get_conf.return_value.get.side_effect = (
conf_manager.ConfStanzaNotExistException
)
logger = mock.MagicMock()
expected_log_level = "INFO"

log_level = conf_manager.get_log_level(
logger=logger,
session_key="session_key",
app_name="app_name",
conf_name="conf_name",
log_stanza="my_logger",
log_level_field="my_field",
)

assert log_level == expected_log_level
assert logger.error.call_count == 1


@mock.patch.object(conf_manager, "ConfManager")
def test_get_log_level_with_default_fields(mock_conf_manager_class):
mock_conf_manager = mock_conf_manager_class.return_value
mock_conf_manager.get_conf.return_value = {"logging": {"loglevel": "WARN"}}
expected_log_level = "WARN"

log_level = conf_manager.get_log_level(
logger=mock.MagicMock(),
session_key="session_key",
app_name="app_name",
conf_name="conf_name",
)

assert log_level == expected_log_level
43 changes: 41 additions & 2 deletions tests/unit/test_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import threading
import traceback
import time
import pytest
from unittest import mock

from solnlib import log
Expand Down Expand Up @@ -193,14 +194,52 @@ def test_modular_input_end():

def test_events_ingested():
with mock.patch("logging.Logger") as mock_logger:
log.events_ingested(mock_logger, "modular_input_name", "sourcetype", 5)
log.events_ingested(
mock_logger, "input_type://input_name", "sourcetype", 5, "default"
)

mock_logger.log.assert_called_once_with(
logging.INFO,
"action=events_ingested modular_input_name=input_type://input_name sourcetype_ingested=sourcetype "
"n_events=5 event_input=input_name event_index=default",
)

with mock.patch("logging.Logger") as mock_logger:
log.events_ingested(
mock_logger,
"demo://modular_input_name",
"sourcetype",
5,
"default",
host="abcd",
account="test_acc",
)

mock_logger.log.assert_called_once_with(
logging.INFO,
"action=events_ingested modular_input_name=modular_input_name sourcetype_ingested=sourcetype n_events=5",
"action=events_ingested modular_input_name=demo://modular_input_name sourcetype_ingested=sourcetype n_"
"events=5 event_input=modular_input_name event_index=default event_account=test_acc event_host=abcd",
)


def test_events_ingested_invalid_input():
exp_msg = "Invalid modular input name: modular_input_name. It should be in format <input_type>://<input_name>"

with pytest.raises(ValueError) as excinfo:
with mock.patch("logging.Logger") as mock_logger:
log.events_ingested(
mock_logger,
"modular_input_name",
"sourcetype",
5,
"default",
host="abcd",
account="test_acc",
)

assert exp_msg == str(excinfo.value)


def test_log_exceptions_full_msg():
start_msg = "some msg before exception"
with mock.patch("logging.Logger") as mock_logger:
Expand Down
Loading