prod/native/libcommon/code/ConfigurationManager.cpp (124 lines of code) (raw):
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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.
*/
#include "ConfigurationManager.h"
#include "CommonUtils.h"
#include <string_view>
#include <cstdlib>
namespace elasticapm::php {
using namespace std::string_literals;
using namespace std::string_view_literals;
std::string ConfigurationManager::accessOptionStringValueByMetadata(OptionMetadata const &metadata, ConfigurationSnapshot const &snapshot) {
switch (metadata.type) {
case OptionMetadata::type::string: {
std::string *value = reinterpret_cast<std::string *>((std::byte *)&snapshot + metadata.offset);
return *value;
}
case OptionMetadata::type::boolean: {
bool *value = reinterpret_cast<bool *>((std::byte *)&snapshot + metadata.offset);
return *value ? "true"s : "false"s;
}
case OptionMetadata::type::duration: {
auto value = reinterpret_cast<std::chrono::milliseconds *>((std::byte *)&snapshot + metadata.offset);
return std::to_string(value->count());
}
case OptionMetadata::type::loglevel: {
LogLevel *value = reinterpret_cast<LogLevel *>((std::byte *)&snapshot + metadata.offset);
std::string_view level = utils::trim(getLogLevelName(*value));
return {level.data(), level.length()};
}
case OptionMetadata::type::bytes: {
std::size_t *value = reinterpret_cast<std::size_t *>((std::byte *)&snapshot + metadata.offset);
return std::to_string(*value);
}
default:
return {};
}
}
ConfigurationManager::optionValue_t ConfigurationManager::getOptionValue(std::string_view optionName, ConfigurationSnapshot const &snapshot) const {
auto option = options_.find(std::string(optionName));
if (option == std::end(options_)) {
return std::nullopt;
}
auto const &metadata = option->second;
switch (metadata.type) {
case elasticapm::php::ConfigurationManager::OptionMetadata::type::string: {
std::string *value = reinterpret_cast<std::string *>((std::byte *)&snapshot + metadata.offset);
return std::string(value->data(), value->length());
}
case elasticapm::php::ConfigurationManager::OptionMetadata::type::boolean: {
bool *value = reinterpret_cast<bool *>((std::byte *)&snapshot + metadata.offset);
return *value;
}
case elasticapm::php::ConfigurationManager::OptionMetadata::type::duration: {
auto value = reinterpret_cast<std::chrono::milliseconds *>((std::byte *)&snapshot + metadata.offset);
return *value;
}
case elasticapm::php::ConfigurationManager::OptionMetadata::type::loglevel: {
LogLevel *value = reinterpret_cast<LogLevel *>((std::byte *)&snapshot + metadata.offset);
return *value;
}
case elasticapm::php::ConfigurationManager::OptionMetadata::type::bytes: {
size_t *value = reinterpret_cast<size_t *>((std::byte *)&snapshot + metadata.offset);
return *value;
}
default:
return std::nullopt;
}
}
void ConfigurationManager::update() {
ConfigurationSnapshot newConfig;
newConfig.revision = getNextRevision();
for (auto const &entry : options_) {
auto optionVal = fetchStringValue(entry.first);
if (!optionVal.has_value()) {
continue; // keep default from snapshot
}
auto &optionValue = optionVal.value();
try {
switch (entry.second.type) {
case OptionMetadata::type::string: {
std::string *value = (std::string *)((std::byte *)&newConfig + entry.second.offset);
value->swap(optionValue);
break;
}
case OptionMetadata::type::boolean: {
bool *value = (bool *)((std::byte *)&newConfig + entry.second.offset);
*value = utils::parseBoolean(optionValue);
break;
}
case OptionMetadata::type::duration: {
auto value = reinterpret_cast<std::chrono::milliseconds *>((std::byte *)&newConfig + entry.second.offset);
*value = utils::convertDurationWithUnit(optionValue);
break;
}
case OptionMetadata::type::loglevel: {
LogLevel *value = (LogLevel *)((std::byte *)&newConfig + entry.second.offset);
*value = utils::parseLogLevel(optionValue);
break;
}
case OptionMetadata::type::bytes: {
std::size_t *value = (std::size_t *)((std::byte *)&newConfig + entry.second.offset);
*value = utils::parseByteUnits(optionValue);
break;
}
}
} catch (std::invalid_argument const &e) {
ELOGF_NF_ERROR(logger_, "ConfigurationManager::update exception: '%s'", e.what());
}
}
//TODO lock
current_ = std::move(newConfig);
}
std::optional<std::string> ConfigurationManager::fetchStringValue(std::string_view name) {
auto iniName = utils::getIniName(name);
auto value = readIniValue_(iniName);
if (value.has_value()) {
return value;
}
auto envValue = getenv(utils::getEnvName(name).c_str());
if (!envValue) {
return std::nullopt;
}
return envValue;
}
uint64_t ConfigurationManager::getNextRevision() {
return (++upcomingConfigRevision_);
}
} // namespace elasticapm::php