Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c3d8fe2
Added CORS OPTIONS support
wsobel Mar 24, 2026
95919c6
Added unit tests
wsobel Mar 24, 2026
fe1f410
Fixed options with specific paths
wsobel Mar 26, 2026
d4edd47
Fixed some of the error messages
wsobel Mar 26, 2026
744c577
Fixed issues with regex based paths
wsobel Mar 26, 2026
19beae1
Changed logging for some error messages on load
wsobel Mar 27, 2026
5f14e3d
Added some fixes for logging directory management. Issue #604
wsobel Apr 7, 2026
9c0a84d
Added some fixes for logging directory management. Issue #604
wsobel Apr 7, 2026
eb456ff
Fixed logging directory creation and placement of rotation files.
Apr 7, 2026
30504b6
Merge branch 'add_options_support_for_cors' of z:\projects\MTConnect\…
Apr 7, 2026
e225df3
Version 2.7.0.6
wsobel Apr 7, 2026
ce2748e
Fixed tests to set log directors as temp for log testing.
wsobel Apr 8, 2026
17f07cc
Added rotation test at 1kb
wsobel Apr 8, 2026
267bcb6
Merge branch 'main' into add_options_support_for_cors
wsobel Apr 8, 2026
1a322cc
Fixed chunk body to remove x86 build warnings.
wsobel Apr 8, 2026
6cf2aea
Formatted code with clang
wsobel Apr 8, 2026
131304b
Remove x86 warnings because of header chunk handler.
wsobel Apr 8, 2026
349702c
Try to reduce cache size for builds
wsobel Apr 8, 2026
1f20cdc
Fixed warnings in tls test
wsobel Apr 8, 2026
3f72593
Upgraded deprecated workflow package references
wsobel Apr 8, 2026
23e376b
See if we can lock down macos target version
wsobel Apr 8, 2026
d3bfa54
Code cleanup after refiew
wsobel Apr 8, 2026
1a6783c
Set the os version in conan for macos to 15
wsobel Apr 8, 2026
1a9f73f
Some build and code cleanup
wsobel Apr 8, 2026
e59e77c
Changed logging to match documentation
wsobel Apr 8, 2026
60c31f8
Version 2.7.0.7
wsobel Apr 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
# checks-out your repository under $GITHUB_WORKSPACE
# see https://github.com/actions/checkout
- name: Checkout Agent
uses: actions/checkout@v3
uses: actions/checkout@v4

# the QEMU emulator lets us build for arm processors also
# see https://github.com/docker/setup-qemu-action
Expand Down
55 changes: 39 additions & 16 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ on:
# Enable automated build once verified
pull_request:
paths-ignore: ["**/*.md", "LICENSE.txt", ".gitignore"]
branches: [ "main", "main-dev" ]
branches: [ "main" ]

push:
paths-ignore: ["**/*.md", "LICENSE.txt", ".gitignore"]
branches: [ "main", "main-dev" ]
branches: [ "main" ]
tags:
- "v*.*.*"

Expand Down Expand Up @@ -64,11 +64,11 @@ jobs:
echo $CTEST_OUTPUT_ON_FAILURE

- name: Checkout Agent
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Cache conan packages
- name: Restore cached conan packages
id: cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ env.CONAN_HOME }}
key: ${{ runner.os }}-build-${{ matrix.profile }}-${{ hashFiles('**/conanfile.py') }}
Expand Down Expand Up @@ -98,6 +98,12 @@ jobs:
set CTEST_OUTPUT_ON_FAILURE=TRUE
conan create . --build=missing -pr conan/profiles/${{ matrix.profile }} -o "&:with_docs=False" -o "&:cpack=True" -o "&:cpack_destination=${{ env.ZIP_DIR }}" -o "&:shared=${{ matrix.shared }}"

- name: Clean conan cache
continue-on-error: true
run: |
conan remove mtconnect_agent -c
conan cache clean "*" --source --build --download

- name: Release
uses: softprops/action-gh-release@v2
if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.shared == 'False' }}
Expand All @@ -123,15 +129,15 @@ jobs:
sudo apt install -y build-essential cmake gcc-11 g++-11 python3 autoconf automake

- name: Checkout Agent
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Cache conan packages
- name: Restore cached conan packages
id: cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/.conan2
key: ${{ runner.os }}-build-${{ matrix.shared }}-${{ hashFiles('**/conanfile.py') }}

- name: Install Conan
uses: turtlebrowser/get-conan@v1.2

Expand All @@ -152,7 +158,14 @@ jobs:
export CTEST_OUTPUT_ON_FAILURE=TRUE
conan create . --build=missing -pr conan/profiles/gcc -o '&:shared=${{ matrix.shared }}' -o '&:with_docs=False' -o '&:cpack=True' -o '&:cpack_name=dist' -o '&:cpack_destination=${{ github.workspace }}'

- name: Cleanse package version
- name: Clean conan cache
continue-on-error: true
run: |
conan remove mtconnect_agent -c
conan cache clean "*" --source --build --download

- name: Derive Package Version
if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.shared == 'False' }}
run: |
PACKAGE_VERSION=${{ github.ref_name }}
if [[ $PACKAGE_VERSION == v*.*.*.* ]]; then
Expand All @@ -162,15 +175,19 @@ jobs:
else
echo "PACKAGE_VERSION=0.0.0.0" >> $GITHUB_ENV
fi

- name: Prepare Debian Package
if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.shared == 'False' }}
shell: bash
working-directory: ${{ github.workspace }}
run: |
mkdir -p pkgroot/home/edge/
ls -lah pkgroot
tar -xzf dist.tar.gz -C pkgroot/
mv pkgroot/dist pkgroot/usr

- name: Create Debian Package
if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.shared == 'False' }}
id: create_debian_package
uses: jiro4989/build-deb-action@v3
with:
Expand All @@ -180,9 +197,10 @@ jobs:
arch: amd64
desc: "MTConnect Agent for Ununtu"
maintainer: Datanomix <support@datanomix.io>

- name: Release
uses: softprops/action-gh-release@v2
if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.shared == 'False' }}
uses: softprops/action-gh-release@v2
with:
name: Version ${{ github.ref_name }}
draft: true
Expand All @@ -199,15 +217,15 @@ jobs:

steps:
- name: Checkout Agent
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Cache conan packages
- name: Restore cached conan packages
id: cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/.conan2
key: ${{ runner.os }}-build-${{ matrix.shared }}-${{ hashFiles('**/conanfile.py') }}

- name: Install Conan
run: |
brew install conan
Expand All @@ -228,4 +246,9 @@ jobs:
run: |
export CTEST_OUTPUT_ON_FAILURE=TRUE
conan create . --build=missing -pr conan/profiles/macos -o '&:shared=${{ matrix.shared }}' -o '&:with_docs=False'


- name: Clean conan cache
continue-on-error: true
run: |
conan remove mtconnect_agent -c
conan cache clean "*" --source --build --download
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set(AGENT_VERSION_MAJOR 2)
set(AGENT_VERSION_MINOR 7)
set(AGENT_VERSION_PATCH 0)
set(AGENT_VERSION_BUILD 5)
set(AGENT_VERSION_BUILD 7)
set(AGENT_VERSION_RC "")

# This minimum version is to support Visual Studio 2019 and C++ feature checking and FetchContent
Expand All @@ -27,7 +27,7 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CXX_COMPILE_FEATURES cxx_std_20)
set(CMAKE_OSX_DEPLOYMENT_TARGET 13.3)
set(CMAKE_OSX_DEPLOYMENT_TARGET 15.0)

project(cppagent LANGUAGES C CXX)

Expand Down
1 change: 1 addition & 0 deletions conan/profiles/macos
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include(default)
[settings]
compiler=apple-clang
compiler.cppstd=20
os.version=15.0

[system_tools]
cmake/>3.26.0
Expand Down
70 changes: 48 additions & 22 deletions src/mtconnect/configuration/agent_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,9 @@ namespace mtconnect::configuration {
cerr << "Loading configuration from:" << *path << endl;

m_configFile = fs::canonical(*path);
addPathFront(m_configPaths, m_configFile.parent_path());
addPathBack(m_dataPaths, m_configFile.parent_path());
m_configPath = m_configFile.parent_path();
addPathFront(m_configPaths, m_configPath);
addPathBack(m_dataPaths, m_configPath);

ifstream file(m_configFile.c_str());
std::stringstream buffer;
Expand Down Expand Up @@ -528,8 +529,8 @@ namespace mtconnect::configuration {

ConfigOptions options;
AddDefaultedOptions(logger, options,
{{"max_size", "10mb"s},
{"rotation_size", "2mb"s},
{{"max_size", "2mb"s},
{"max_archive_size", "10mb"s},
{"max_index", 9},
{"file_name", defaultFileName},
{"archive_pattern", defaultArchivePattern}});
Expand Down Expand Up @@ -593,15 +594,16 @@ namespace mtconnect::configuration {
}
}

auto &maxLogFileSize = logChannel.m_maxLogFileSize;
auto &maxLogArchiveSize = logChannel.m_maxLogArchiveSize;
auto &logRotationSize = logChannel.m_logRotationSize;
auto &rotationLogInterval = logChannel.m_rotationLogInterval;
auto &logArchivePattern = logChannel.m_logArchivePattern;
auto &logDirectory = logChannel.m_logDirectory;
auto &archiveLogDirectory = logChannel.m_archiveLogDirectory;
auto &logFileName = logChannel.m_logFileName;

maxLogFileSize = ConvertFileSize(options, "max_size", maxLogFileSize);
logRotationSize = ConvertFileSize(options, "rotation_size", logRotationSize);
maxLogArchiveSize = ConvertFileSize(options, "max_archive_size", maxLogArchiveSize);
logRotationSize = ConvertFileSize(options, "max_size", logRotationSize);
int max_index = *GetOption<int>(options, "max_index");

if (auto sched = GetOption<string>(options, "schedule"))
Expand All @@ -618,29 +620,51 @@ namespace mtconnect::configuration {
auto file_name = *GetOption<string>(options, "file_name");
auto archive_pattern = *GetOption<string>(options, "archive_pattern");

// Default the log directory to the configuration file path.
logDirectory = m_configPath;
logFileName = fs::path(file_name);
logArchivePattern = fs::path(archive_pattern);
if (!logArchivePattern.has_filename())

// Determine the log directory based on the provided file name and archive pattern
if (logFileName.is_absolute())
logDirectory = logFileName.parent_path();
else if (logArchivePattern.is_absolute())
logDirectory = logArchivePattern.parent_path();

// If the log file name is relative and has a parent path, use it to determine the log directory
if (logFileName.is_relative() && logFileName.has_parent_path())
{
logArchivePattern = logArchivePattern / archiveFileName(get<string>(options["file_name"]));
logDirectory = logDirectory / logFileName.parent_path();
logFileName = logFileName.filename();
}
else if (logArchivePattern.is_relative() && logArchivePattern.has_parent_path())
{
logDirectory = logDirectory / logArchivePattern.parent_path();
logArchivePattern = logArchivePattern.filename();
}

if (logArchivePattern.is_relative())
logArchivePattern = fs::current_path() / logArchivePattern;
// Make sure the log archive pattern includes a file name, use the default file name as the
// base.
if (!logArchivePattern.has_filename())
logArchivePattern = logArchivePattern / archiveFileName(get<string>(options["file_name"]));

// Get the log directory from the archive path.
logDirectory = logArchivePattern.parent_path();
// Make the logArchivePattern and logFileName absolute paths
logDirectory = logDirectory.lexically_normal();

// If the file name does not specify a log directory, use the
// archive directory
logFileName = fs::path(file_name);
if (!logFileName.has_parent_path())
if (logArchivePattern.is_relative())
logArchivePattern = logDirectory / logArchivePattern;
logArchivePattern = logArchivePattern.lexically_normal();
archiveLogDirectory = logArchivePattern.parent_path();
fs::create_directories(archiveLogDirectory);

if (logFileName.is_relative())
logFileName = logDirectory / logFileName;
else if (logFileName.is_relative())
logFileName = fs::current_path() / logFileName;
logFileName = logFileName.lexically_normal();
fs::create_directories(logFileName.parent_path());

// Create a text file sink
auto sink = boost::make_shared<text_sink>(
kw::file_name = logFileName, kw::target_file_name = logArchivePattern.filename(),
kw::file_name = logFileName.string(), kw::target_file_name = logArchivePattern.string(),
kw::auto_flush = true, kw::rotation_size = logRotationSize,
kw::open_mode = ios_base::out | ios_base::app, kw::format = formatter);

Expand All @@ -649,7 +673,8 @@ namespace mtconnect::configuration {

// Set up where the rotated files will be stored
sink->locked_backend()->set_file_collector(logr::sinks::file::make_collector(
kw::target = logDirectory, kw::max_size = maxLogFileSize, kw::max_files = max_index));
kw::target = archiveLogDirectory.string(), kw::max_size = maxLogArchiveSize,
kw::max_files = max_index));

if (rotationLogInterval > 0)
{
Expand Down Expand Up @@ -1248,7 +1273,8 @@ namespace mtconnect::configuration {
}
catch (exception &e)
{
LOG(info) << "Cannot load plugin " << name << " from " << path << " Reason: " << e.what();
LOG(debug) << "Plugin " << name << " from " << path << " not found, Reason: " << e.what()
<< ", trying next path if available.";
}
}

Expand Down
28 changes: 21 additions & 7 deletions src/mtconnect/configuration/agent_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,17 +183,25 @@ namespace mtconnect {
{
return m_logChannels[channelName].m_logArchivePattern;
}

/// @brief gets the archive log directory
/// @return log directory
const auto &getArchiveLogDirectory(const std::string &channelName = "agent")
{
return m_logChannels[channelName].m_archiveLogDirectory;
}

/// @brief Get the maximum size of all the log files
/// @return the maximum size of all log files
auto getMaxLogFileSize(const std::string &channelName = "agent")
auto getLogRotationSize(const std::string &channelName = "agent")
{
return m_logChannels[channelName].m_maxLogFileSize;
return m_logChannels[channelName].m_logRotationSize;
}
/// @brief the maximum size of a log file when it triggers rolling over
/// @return the maxumum site of a log file
auto getLogRotationSize(const std::string &channelName = "agent")
auto getMaxLogArchiveSize(const std::string &channelName = "agent")
{
return m_logChannels[channelName].m_logRotationSize;
return m_logChannels[channelName].m_maxLogArchiveSize;
}
/// @brief How often to roll over the log file
///
Expand Down Expand Up @@ -260,6 +268,10 @@ namespace mtconnect {
/// @param path the path to add
void addPluginPath(const std::filesystem::path &path) { addPathBack(m_pluginPaths, path); }

///@brief set the config path for testing
///@param path the path to set for the config file directory
void setConfigPath(const std::filesystem::path &path) { m_configPath = path; }

protected:
DevicePtr getDefaultDevice();
void loadAdapters(const ptree &tree, const ConfigOptions &options);
Expand Down Expand Up @@ -295,7 +307,7 @@ namespace mtconnect {
else
{
LOG(debug) << "Cannot find file '" << file << "' "
<< " in path " << path;
<< " in path " << path << ", continuing...";
}
}

Expand All @@ -312,7 +324,7 @@ namespace mtconnect {
if (!ec)
paths.emplace_back(con);
else
LOG(debug) << "Cannot file path: " << path << ", " << ec.message();
LOG(debug) << "Cannot find path: " << path << ", " << ec.message() << ", skipping...";
}

void addPathFront(std::list<std::filesystem::path> &paths, std::filesystem::path path)
Expand Down Expand Up @@ -348,10 +360,11 @@ namespace mtconnect {
{
std::string m_channelName;
std::filesystem::path m_logDirectory;
std::filesystem::path m_archiveLogDirectory;
std::filesystem::path m_logArchivePattern;
std::filesystem::path m_logFileName;

int64_t m_maxLogFileSize {0};
int64_t m_maxLogArchiveSize {0};
int64_t m_logRotationSize {0};
int64_t m_rotationLogInterval {0};

Expand All @@ -374,6 +387,7 @@ namespace mtconnect {
std::string m_devicesFile;
std::filesystem::path m_exePath;
std::filesystem::path m_working;
std::filesystem::path m_configPath;

std::list<std::filesystem::path> m_configPaths;
std::list<std::filesystem::path> m_dataPaths;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ namespace mtconnect {
Requirement("Rotation", ValueType::VECTOR, 3, false),
Requirement("TranslationDataSet", ValueType::DATA_SET, false),
Requirement("RotationDataSet", ValueType::DATA_SET, false)});
transformation->setOrder({"Translation", "TranslationDataSet", "Rotation", "RotationDataSet"});
transformation->setOrder(
{"Translation", "TranslationDataSet", "Rotation", "RotationDataSet"});

auto coordinateSystem = make_shared<Factory>(Requirements {
Requirement("id", true), Requirement("name", false), Requirement("nativeName", false),
Expand Down
Loading
Loading