Skip to content

Commit

Permalink
Add SW_APM_EXPERIMENTAL_OTEL_COLLECTOR config
Browse files Browse the repository at this point in the history
  • Loading branch information
tammy-baylis-swi committed Oct 19, 2023
1 parent 78da6b6 commit dfaf5e8
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 1 deletion.
28 changes: 27 additions & 1 deletion solarwinds_apm/apm_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,12 @@ class SolarWindsApmConfig:

_CONFIG_FILE_DEFAULT = "./solarwinds-apm-config.json"
_DELIMITER = "."
_EXP_KEYS = ["otel_collector"]
_EXP_PREFIX = "experimental_"
_KEY_MASK = "{}...{}:{}"
_KEY_MASK_BAD_FORMAT = "{}...<invalid_format>"
_KEY_MASK_BAD_FORMAT_SHORT = "{}<invalid_format>"
_SW_PREFIX = "sw_apm_"

def __init__(
self,
Expand Down Expand Up @@ -109,6 +112,7 @@ def __init__(
"reporter_file_single": 0,
"proxy": "",
"transaction_filters": [],
"experimental": {},
}
self.agent_enabled = True
self.update_with_cnf_file()
Expand Down Expand Up @@ -611,7 +615,10 @@ def update_with_env_var(self) -> None:
if key == "transaction":
# we do not allow complex config options to be set via environment variables
continue
env = "SW_APM_" + key.upper()
if key == "experimental":
# but we do allow flat SW_APM_EXPERIMENTAL_OTEL_COLLECTOR setting to match js
key = self._EXP_PREFIX + "otel_collector"
env = (self._SW_PREFIX + key).upper()
val = os.environ.get(env)
if val is not None:
self._set_config_value(key, val)
Expand Down Expand Up @@ -708,6 +715,25 @@ def _set_config_value(self, keys_str: str, val: Any) -> Any:
self.__config[key] = val
# update logging level of agent logger
apm_logging.set_sw_log_level(val)
elif keys == ["experimental"]:
for exp_k, exp_v in val.items():
if exp_k in self._EXP_KEYS:
exp_v = self.convert_to_bool(exp_v)
if exp_v is None:
logger.warning(
"Ignore invalid config of experimental %s",
exp_k,
)
else:
self.__config["experimental"][exp_k] = exp_v
elif keys == ["experimental_otel_collector"]:
val = self.convert_to_bool(val)
if val is None:
logger.warning(
"Ignore invalid config of experimental otel_collector"
)
else:
self.__config["experimental"]["otel_collector"] = val
elif isinstance(sub_dict, dict) and keys[-1] in sub_dict:
if isinstance(sub_dict[keys[-1]], bool):
val = self.convert_to_bool(val)
Expand Down
6 changes: 6 additions & 0 deletions solarwinds_apm/configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ def _configure_metrics_exporter(
logger.error("Tracing disabled. Cannot set metrics exporter.")
return

if not apm_config.get("experimental").get("otel_collector") is True:
logger.debug(
"Experimental otel_collector flag not configured. Not setting metrics exporter."
)
return

# SolarWindsDistro._configure does not setdefault so this
# could be None
environ_exporter = os.environ.get(
Expand Down
98 changes: 98 additions & 0 deletions tests/unit/test_apm_config/test_apm_config_experimental.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# © 2023 SolarWinds Worldwide, LLC. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

import os

from solarwinds_apm import apm_config


def helper_mock_common(mocker):
mock_iter_entry_points = mocker.patch(
"solarwinds_apm.apm_config.iter_entry_points"
)
mock_points = mocker.MagicMock()
mock_points.__iter__.return_value = ["foo"]
mock_iter_entry_points.configure_mock(
return_value=mock_points
)

class TestSolarWindsApmConfigExperimental:
def test_experimental_default(
self,
mocker,
):
helper_mock_common(mocker)
mocker.patch.dict(os.environ, {
"SW_APM_SERVICE_KEY": "valid:key",
})
resulting_config = apm_config.SolarWindsApmConfig()
assert resulting_config.get("experimental") == {}

def test_experimental_env_var_otelcol_not_bool(
self,
mocker,
):
helper_mock_common(mocker)
mocker.patch.dict(os.environ, {
"SW_APM_SERVICE_KEY": "valid:key",
"SW_APM_EXPERIMENTAL_OTEL_COLLECTOR": "foo"
})
resulting_config = apm_config.SolarWindsApmConfig()
assert resulting_config.get("experimental") == {}

def test_experimental_env_var_otelcol_true(
self,
mocker,
):
helper_mock_common(mocker)
mocker.patch.dict(os.environ, {
"SW_APM_SERVICE_KEY": "valid:key",
"SW_APM_EXPERIMENTAL_OTEL_COLLECTOR": "true"
})
resulting_config = apm_config.SolarWindsApmConfig()
assert resulting_config.get("experimental") == {"otel_collector": True}

def test_experimental_cnf_file_otelcol_not_bool(
self,
mocker,
):
helper_mock_common(mocker)
mocker.patch.dict(os.environ, {
"SW_APM_SERVICE_KEY": "valid:key",
})
mock_get_cnf_dict = mocker.patch(
"solarwinds_apm.apm_config.SolarWindsApmConfig.get_cnf_dict"
)
mock_get_cnf_dict.configure_mock(
return_value={
"experimental": {
"otel_collector": "foo",
},
}
)
resulting_config = apm_config.SolarWindsApmConfig()
assert resulting_config.get("experimental") == {}

def test_experimental_cnf_file_otelcol_true(
self,
mocker,
):
helper_mock_common(mocker)
mocker.patch.dict(os.environ, {
"SW_APM_SERVICE_KEY": "valid:key",
})
mock_get_cnf_dict = mocker.patch(
"solarwinds_apm.apm_config.SolarWindsApmConfig.get_cnf_dict"
)
mock_get_cnf_dict.configure_mock(
return_value={
"experimental": {
"otel_collector": True,
},
}
)
resulting_config = apm_config.SolarWindsApmConfig()
assert resulting_config.get("experimental") == {"otel_collector": True}

0 comments on commit dfaf5e8

Please sign in to comment.