This is an automated email from the ASF dual-hosted git repository.
aboda pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
The following commit(s) were added to refs/heads/master by this push:
new 7d18dc8 MINIFICPP-1088 - clean up minifiexe and MINIFI_HOME logic
7d18dc8 is described below
commit 7d18dc8501ffa884f642d7f5836a12983c6719b1
Author: Daniel Bakai <[email protected]>
AuthorDate: Wed Jan 15 11:58:01 2020 +0100
MINIFICPP-1088 - clean up minifiexe and MINIFI_HOME logic
Signed-off-by: Arpad Boda <[email protected]>
This closes #709
---
CMakeLists.txt | 4 +
LICENSE | 35 ++
NOTICE | 4 +
cmake/FindMessageCompiler.cmake | 51 +++
conf/minifi-log.properties | 2 +
controller/CMakeLists.txt | 2 +-
controller/MiNiFiController.cpp | 42 +--
extensions/librdkafka/KafkaConnection.h | 2 +
extensions/opc/include/opc.h | 1 +
extensions/opencv/OpenCVLoader.h | 3 +-
extensions/sftp/processors/ListSFTP.h | 1 +
libminifi/CMakeLists.txt | 16 +
libminifi/include/core/logging/Logger.h | 112 +-----
.../include/core/logging/LoggerConfiguration.h | 9 +-
.../include/core/logging/WindowsEventLogSink.h | 71 ++++
libminifi/include/properties/Properties.h | 15 +-
libminifi/include/utils/Environment.h | 97 +++++
libminifi/include/utils/file/PathUtils.h | 10 +-
libminifi/src/Properties.cpp | 24 +-
libminifi/src/core/logging/Logger.cpp | 146 ++++++++
libminifi/src/core/logging/LoggerConfiguration.cpp | 31 +-
libminifi/src/core/logging/WindowsEventLogSink.cpp | 95 +++++
.../src/core/logging/WindowsMessageTextFile.mc | 24 ++
libminifi/src/utils/Environment.cpp | 185 ++++++++++
libminifi/src/utils/StringUtils.cpp | 18 +-
libminifi/src/utils/file/PathUtils.cpp | 35 ++
libminifi/test/TestBase.cpp | 15 +
libminifi/test/TestBase.h | 15 +-
libminifi/test/unit/EnvironmentUtilsTests.cpp | 154 ++++++++
libminifi/test/unit/FileUtilsTests.cpp | 32 ++
libminifi/test/unit/StringUtilsTests.cpp | 17 +-
main/CMakeLists.txt | 7 +-
main/MainHelper.cpp | 172 +++++++++
main/{Main.h => MainHelper.h} | 96 ++---
main/MiNiFiMain.cpp | 390 ++++++++++-----------
main/MiNiFiWindowsService.cpp | 43 ++-
main/MiNiFiWindowsService.h | 22 +-
msi/WixWin.wsi | 9 +-
nanofi/include/cxx/Plan.h | 1 +
39 files changed, 1503 insertions(+), 505 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 02098e2..49703b0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -224,6 +224,9 @@ endif()
# spdlog
add_library(spdlog INTERFACE)
target_include_directories(spdlog INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/spdlog-20170710/include")
+if (NOT WIN32)
+ set_property(TARGET spdlog APPEND PROPERTY
INTERFACE_COMPILE_DEFINITIONS "SPDLOG_ENABLE_SYSLOG")
+endif()
# yaml-cpp
include(BundledYamlCpp)
@@ -506,6 +509,7 @@ if(WIN32)
set(CPACK_COMPONENT_LIBRARIES_INSTALL_TYPES Developer Full)
set(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer Full)
set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full)
+ set(CPACK_WIX_EXTENSIONS WixUtilExtension)
set(CPACK_WIX_UI_BANNER
"${CMAKE_CURRENT_SOURCE_DIR}/msi/minifi-logo-png-banner.png")
set(CPACK_WIX_UI_DIALOG "${CMAKE_CURRENT_SOURCE_DIR}/msi/bgr.png")
diff --git a/LICENSE b/LICENSE
index c51aa71..550083e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2629,3 +2629,38 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+
+This product bundles 'POCO C++ Libraries' under a BSL-1.0 license:
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+---------------------------------------------------------------------------
+Note:
+Individual files contain the following tag instead of the full license text.
+
+ SPDX-License-Identifier: BSL-1.0
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are here available: http://spdx.org/licenses/
diff --git a/NOTICE b/NOTICE
index a62ca67..cec2420 100644
--- a/NOTICE
+++ b/NOTICE
@@ -29,6 +29,10 @@ The derived work is adapted from
Modules/FindPatch.cmake
and can be found in cmake/FindPatch.cmake
+This includes derived works from the 'POCO C++ Libraries' (BSL-1.0 licensed)
project (https://github.com/pocoproject/poco):
+The derived work is adapted from
+ cmake/PocoMacros.cmake and can be found in cmake/FindMessageCompiler.cmake
+
This bundles the 'AWS SDK for C++' (ALv2 licensed) project
(https://github.com/aws/aws-sdk-cpp/), which includes the following NOTICE:
AWS SDK for C++
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
diff --git a/cmake/FindMessageCompiler.cmake b/cmake/FindMessageCompiler.cmake
new file mode 100644
index 0000000..22c1a70
--- /dev/null
+++ b/cmake/FindMessageCompiler.cmake
@@ -0,0 +1,51 @@
+# Copyright Siemens AG, 2014
+# Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
+# and Contributors.
+#
+# SPDX-License-Identifier: BSL-1.0
+#
+# Collection of common functionality for Poco CMake
+
+# Find the Microsoft mc.exe message compiler
+#
+# CMAKE_MC_COMPILER - where to find mc.exe
+if (WIN32)
+ # cmake has CMAKE_RC_COMPILER, but no message compiler
+ if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
+ # this path is only present for 2008+, but we currently require PATH to
+ # be set up anyway
+ get_filename_component(sdk_dir
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft
SDKs\\Windows;CurrentInstallFolder]" REALPATH)
+ get_filename_component(kit_dir
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed
Roots;KitsRoot]" REALPATH)
+ get_filename_component(kit81_dir
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed
Roots;KitsRoot81]" REALPATH)
+ get_filename_component(kit10_dir
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed
Roots;KitsRoot10]" REALPATH)
+ get_filename_component(kit10wow_dir
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows Kits\\Installed
Roots;KitsRoot10]" REALPATH)
+ file(GLOB kit10_list ${kit10_dir}/bin/10.* ${kit10wow_dir}/bin/10.*)
+ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(env_bindir "$ENV{WindowsSdkVerBinPath}/x64")
+ set(sdk_bindir "${sdk_dir}/bin/x64")
+ set(kit_bindir "${kit_dir}/bin/x64")
+ set(kit81_bindir "${kit81_dir}/bin/x64")
+ foreach (tmp_elem ${kit10_list})
+ if (IS_DIRECTORY ${tmp_elem})
+ list(APPEND kit10_bindir "${tmp_elem}/x64")
+ endif()
+ endforeach()
+ else ()
+ set(env_bindir "$ENV{WindowsSdkVerBinPath}/x86")
+ set(sdk_bindir "${sdk_dir}/bin")
+ set(kit_bindir "${kit_dir}/bin/x86")
+ set(kit81_bindir "${kit81_dir}/bin/x86")
+ foreach (tmp_elem ${kit10_list})
+ if (IS_DIRECTORY ${tmp_elem})
+ list(APPEND kit10_bindir "${tmp_elem}/x86")
+ endif()
+ endforeach()
+ endif ()
+ endif ()
+ find_program(CMAKE_MC_COMPILER mc.exe HINTS "${env_bindir}"
"${sdk_bindir}" "${kit_bindir}" "${kit81_bindir}" "${kit10_bindir}"
+ DOC "path to message compiler")
+
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(MessageCompiler
+ REQUIRED_VARS CMAKE_MC_COMPILER)
+endif(WIN32)
diff --git a/conf/minifi-log.properties b/conf/minifi-log.properties
index 7105ced..250cb46 100644
--- a/conf/minifi-log.properties
+++ b/conf/minifi-log.properties
@@ -35,6 +35,8 @@ appender.rolling.max_file_size=5242880
#appender.stdout=stdout
#appender.stderr=stderr
#appender.null=null
+## The syslog appender will log using syslog(3) on *nix, and to the Windows
Event Log on Windows
+#appender.syslog=syslog
logger.root=INFO,rolling
diff --git a/controller/CMakeLists.txt b/controller/CMakeLists.txt
index 3e35b76..f04d2b0 100644
--- a/controller/CMakeLists.txt
+++ b/controller/CMakeLists.txt
@@ -46,7 +46,7 @@ else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support.
Please use a different C++ compiler.")
endif()
-add_executable(minificontroller MiNiFiController.cpp)
+add_executable(minificontroller MiNiFiController.cpp ../main/MainHelper.cpp)
if(THREADS_HAVE_PTHREAD_ARG)
target_compile_options(PUBLIC minificontroller "-pthread")
endif()
diff --git a/controller/MiNiFiController.cpp b/controller/MiNiFiController.cpp
index c87dbfa..437e770 100644
--- a/controller/MiNiFiController.cpp
+++ b/controller/MiNiFiController.cpp
@@ -31,7 +31,7 @@
#include "core/ConfigurationFactory.h"
#include "core/RepositoryFactory.h"
#include "FlowController.h"
-#include "Main.h"
+#include "MainHelper.h"
#include "properties/Configure.h"
#include "Controller.h"
#include "c2/ControllerSocketProtocol.h"
@@ -42,42 +42,10 @@ int main(int argc, char **argv) {
std::shared_ptr<logging::Logger> logger =
logging::LoggerConfiguration::getConfiguration().getLogger("controller");
- // assumes POSIX compliant environment
- std::string minifiHome;
- if (const char *env_p = std::getenv(MINIFI_HOME_ENV_KEY)) {
- minifiHome = env_p;
- logger->log_info("Using MINIFI_HOME=%s from environment.", minifiHome);
- } else {
- logger->log_info("MINIFI_HOME is not set; determining based on
environment.");
- char *path = nullptr;
- char full_path[PATH_MAX];
- path = realpath(argv[0], full_path);
-
- if (path != nullptr) {
- std::string minifiHomePath(path);
- if (minifiHomePath.find_last_of("/\\") != std::string::npos) {
- minifiHomePath = minifiHomePath.substr(0,
minifiHomePath.find_last_of("/\\")); //Remove /minifi from path
- minifiHome = minifiHomePath.substr(0,
minifiHomePath.find_last_of("/\\")); //Remove /bin from path
- }
- }
-
- // attempt to use cwd as MINIFI_HOME
- if (minifiHome.empty() || !validHome(minifiHome)) {
- char cwd[PATH_MAX];
- #ifdef WIN32
- _getcwd(cwd,PATH_MAX);
- #else
- getcwd(cwd, PATH_MAX);
- #endif
- minifiHome = cwd;
- }
-
- }
-
- if (!validHome(minifiHome)) {
- logger->log_error("No valid MINIFI_HOME could be inferred. "
- "Please set MINIFI_HOME or run minifi from a valid
location.");
- //return -1;
+ const std::string minifiHome = determineMinifiHome(logger);
+ if (minifiHome.empty()) {
+ // determineMinifiHome already logged everything we need
+ return -1;
}
std::shared_ptr<minifi::Configure> configuration =
std::make_shared<minifi::Configure>();
diff --git a/extensions/librdkafka/KafkaConnection.h
b/extensions/librdkafka/KafkaConnection.h
index 774754b..5daf96d 100644
--- a/extensions/librdkafka/KafkaConnection.h
+++ b/extensions/librdkafka/KafkaConnection.h
@@ -21,6 +21,8 @@
#include <atomic>
#include <mutex>
#include <string>
+#include <unordered_map>
+
#include "core/logging/LoggerConfiguration.h"
#include "core/logging/Logger.h"
#include "rdkafka.h"
diff --git a/extensions/opc/include/opc.h b/extensions/opc/include/opc.h
index 0a954de..dddfc83 100644
--- a/extensions/opc/include/opc.h
+++ b/extensions/opc/include/opc.h
@@ -27,6 +27,7 @@
#include <string>
#include <functional>
+#include <map>
namespace org {
namespace apache {
diff --git a/extensions/opencv/OpenCVLoader.h b/extensions/opencv/OpenCVLoader.h
index e5a589a..9a6f813 100644
--- a/extensions/opencv/OpenCVLoader.h
+++ b/extensions/opencv/OpenCVLoader.h
@@ -20,6 +20,7 @@
#include "CaptureRTSPFrame.h"
#include "core/ClassLoader.h"
+#include "utils/Environment.h"
class OpenCVObjectFactoryInitializer : public core::ObjectFactoryInitializer {
public:
@@ -29,7 +30,7 @@ class OpenCVObjectFactoryInitializer : public
core::ObjectFactoryInitializer {
// Note:
// 1. OpenCV community are trying to find a better approach than setenv.
// 2. The command will not overwrite value if
"OPENCV_FFMPEG_CAPTURE_OPTIONS" already exists.
- return setenv("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp", 0) ==
0;
+ return
utils::Environment::setEnvironmentVariable("OPENCV_FFMPEG_CAPTURE_OPTIONS",
"rtsp_transport;udp", false /*overwrite*/);
}
virtual void deinitialize() {
diff --git a/extensions/sftp/processors/ListSFTP.h
b/extensions/sftp/processors/ListSFTP.h
index f1017f6..1efb754 100644
--- a/extensions/sftp/processors/ListSFTP.h
+++ b/extensions/sftp/processors/ListSFTP.h
@@ -22,6 +22,7 @@
#include <map>
#include <chrono>
#include <cstdint>
+#include <unordered_map>
#include "SFTPProcessorBase.h"
#include "utils/ByteArrayCallback.h"
diff --git a/libminifi/CMakeLists.txt b/libminifi/CMakeLists.txt
index 6c89eef..b99213e 100644
--- a/libminifi/CMakeLists.txt
+++ b/libminifi/CMakeLists.txt
@@ -91,10 +91,26 @@ endif()
file(GLOB SOURCES "src/utils/file/*.cpp" "src/sitetosite/*.cpp"
"src/core/logging/*.cpp" "src/core/state/*.cpp" "src/core/state/nodes/*.cpp"
"src/c2/protocols/*.cpp" "src/c2/triggers/*.cpp" "src/c2/*.cpp" "src/io/*.cpp"
${SOCKET_SOURCES} ${TLS_SOURCES} "src/core/controller/*.cpp"
"src/controllers/*.cpp" "src/core/*.cpp" "src/core/repository/*.cpp"
"src/core/yaml/*.cpp" "src/core/reporting/*.cpp" "src/provenance/*.cpp"
"src/utils/*.cpp" "src/*.cpp")
+if(WIN32)
+ include(FindMessageCompiler)
+ find_package(MessageCompiler REQUIRED)
+ add_custom_target(message-strings
+ COMMAND "${CMAKE_MC_COMPILER}"
-U "${CMAKE_CURRENT_SOURCE_DIR}/src/core/logging/WindowsMessageTextFile.mc" -h
"${CMAKE_CURRENT_BINARY_DIR}/include/core/logging" -r
"${CMAKE_CURRENT_BINARY_DIR}/src/core/logging"
+ DEPENDS
"src/core/logging/WindowsMessageTextFile.mc"
+ BYPRODUCTS
"include/core/logging/WindowsMessageTextFile.h"
"src/core/logging/WindowsMessageTextFile.rc")
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/src/core/logging")
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/core/logging")
+endif()
+
file(GLOB PROCESSOR_SOURCES "src/processors/*.cpp" )
add_library(core-minifi STATIC ${SOURCES})
+if(WIN32)
+ add_dependencies(core-minifi message-strings)
+ target_include_directories(core-minifi PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/include")
+endif()
+
target_link_libraries(core-minifi ${CMAKE_DL_LIBS} yaml-cpp ZLIB::ZLIB
concurrentqueue RapidJSON spdlog cron)
if(NOT WIN32)
target_link_libraries(core-minifi OSSP::libuuid++)
diff --git a/libminifi/include/core/logging/Logger.h
b/libminifi/include/core/logging/Logger.h
index 4b8be46..f8321f9 100644
--- a/libminifi/include/core/logging/Logger.h
+++ b/libminifi/include/core/logging/Logger.h
@@ -23,7 +23,8 @@
#include <sstream>
#include <iostream>
-#include "spdlog/spdlog.h"
+#include "spdlog/common.h"
+#include "spdlog/logger.h"
namespace org {
namespace apache {
@@ -36,18 +37,12 @@ namespace logging {
class LoggerControl {
public:
- LoggerControl()
- : is_enabled_(true) {
+ LoggerControl();
- }
+ bool is_enabled() const;
- bool is_enabled(){
- return is_enabled_;
- }
+ void setEnabled(bool status);
- void setEnabled(bool status){
- is_enabled_ = status;
- }
protected:
std::atomic<bool> is_enabled_;
};
@@ -85,14 +80,11 @@ typedef enum {
class BaseLogger {
public:
- virtual ~BaseLogger() {
+ virtual ~BaseLogger();
- }
virtual void log_string(LOG_LEVEL level, std::string str) = 0;
- virtual bool should_log(const LOG_LEVEL &level) {
- return true;
- }
+ virtual bool should_log(const LOG_LEVEL &level);
};
@@ -102,27 +94,13 @@ class BaseLogger {
*/
class LogBuilder {
public:
- LogBuilder(BaseLogger *l, LOG_LEVEL level)
- : ignore(false),
- ptr(l),
- level(level) {
- if (!l->should_log(level)) {
- setIgnore();
- }
- }
+ LogBuilder(BaseLogger *l, LOG_LEVEL level);
- ~LogBuilder() {
- if (!ignore)
- log_string(level);
- }
+ ~LogBuilder();
- void setIgnore() {
- ignore = true;
- }
+ void setIgnore();
- void log_string(LOG_LEVEL level) {
- ptr->log_string(level, str.str());
- }
+ void log_string(LOG_LEVEL level);
template<typename T>
LogBuilder &operator<<(const T &o) {
@@ -189,73 +167,15 @@ class Logger : public BaseLogger {
log(spdlog::level::trace, format, args...);
}
- bool should_log(const LOG_LEVEL &level) {
- if (controller_ && !controller_->is_enabled())
- return false;
- spdlog::level::level_enum logger_level = spdlog::level::level_enum::info;
- switch (level) {
- case critical:
- logger_level = spdlog::level::level_enum::critical;
- break;
- case err:
- logger_level = spdlog::level::level_enum::err;
- break;
- case info:
- break;
- case debug:
- logger_level = spdlog::level::level_enum::debug;
- break;
- case off:
- logger_level = spdlog::level::level_enum::off;
- break;
- case trace:
- logger_level = spdlog::level::level_enum::trace;
- break;
- case warn:
- logger_level = spdlog::level::level_enum::warn;
- break;
- }
-
- std::lock_guard<std::mutex> lock(mutex_);
- if (!delegate_->should_log(logger_level)) {
- return false;
- }
- return true;
- }
+ bool should_log(const LOG_LEVEL &level);
protected:
- virtual void log_string(LOG_LEVEL level, std::string str) {
- switch (level) {
- case critical:
- log_warn(str.c_str());
- break;
- case err:
- log_error(str.c_str());
- break;
- case info:
- log_info(str.c_str());
- break;
- case debug:
- log_debug(str.c_str());
- break;
- case trace:
- log_trace(str.c_str());
- break;
- case warn:
- log_warn(str.c_str());
- break;
- case off:
- break;
- }
- }
- Logger(std::shared_ptr<spdlog::logger> delegate,
std::shared_ptr<LoggerControl> controller)
- : delegate_(delegate), controller_(controller) {
- }
+ virtual void log_string(LOG_LEVEL level, std::string str);
- Logger(std::shared_ptr<spdlog::logger> delegate)
- : delegate_(delegate), controller_(nullptr) {
- }
+ Logger(std::shared_ptr<spdlog::logger> delegate,
std::shared_ptr<LoggerControl> controller);
+
+ Logger(std::shared_ptr<spdlog::logger> delegate);
std::shared_ptr<spdlog::logger> delegate_;
diff --git a/libminifi/include/core/logging/LoggerConfiguration.h
b/libminifi/include/core/logging/LoggerConfiguration.h
index ea714e9..7cbbcf5 100644
--- a/libminifi/include/core/logging/LoggerConfiguration.h
+++ b/libminifi/include/core/logging/LoggerConfiguration.h
@@ -24,7 +24,9 @@
#include <map>
#include <mutex>
#include <string>
-#include "spdlog/spdlog.h"
+#include "spdlog/common.h"
+#include "spdlog/sinks/sink.h"
+#include "spdlog/logger.h"
#include "spdlog/formatter.h"
#include "core/Core.h"
@@ -118,12 +120,17 @@ class LoggerConfiguration {
* Can be used to get arbitrarily named Logger, LoggerFactory should be
preferred within a class.
*/
std::shared_ptr<Logger> getLogger(const std::string &name);
+
static const char *spdlog_default_pattern;
+
protected:
static std::shared_ptr<internal::LoggerNamespace>
initialize_namespaces(const std::shared_ptr<LoggerProperties>
&logger_properties);
static std::shared_ptr<spdlog::logger> get_logger(std::shared_ptr<Logger>
logger, const std::shared_ptr<internal::LoggerNamespace> &root_namespace, const
std::string &name,
std::shared_ptr<spdlog::formatter> formatter, bool remove_if_present = false);
private:
+ static std::shared_ptr<spdlog::sinks::sink> create_syslog_sink();
+ static std::shared_ptr<spdlog::sinks::sink> create_fallback_sink();
+
static std::shared_ptr<internal::LoggerNamespace> create_default_root();
class LoggerImpl : public Logger {
diff --git a/libminifi/include/core/logging/WindowsEventLogSink.h
b/libminifi/include/core/logging/WindowsEventLogSink.h
new file mode 100644
index 0000000..9c9bbe0
--- /dev/null
+++ b/libminifi/include/core/logging/WindowsEventLogSink.h
@@ -0,0 +1,71 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+
+#pragma once
+
+#ifdef WIN32
+
+#include "spdlog/common.h"
+#include "spdlog/sinks/base_sink.h"
+#include "spdlog/details/log_msg.h"
+#include "spdlog/details/null_mutex.h"
+
+#include <Windows.h>
+
+#include <string>
+
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace core {
+namespace logging {
+namespace internal {
+
+class windowseventlog_sink : public
spdlog::sinks::base_sink<spdlog::details::null_mutex> {
+ private:
+ HANDLE event_source_;
+
+ WORD type_from_level(const spdlog::details::log_msg& msg) const;
+
+ protected:
+ virtual void _sink_it(const spdlog::details::log_msg& msg);
+
+ virtual void _flush();
+
+ public:
+ windowseventlog_sink(const std::string& source_name = "ApacheNiFiMiNiFi");
+
+ virtual ~windowseventlog_sink();
+
+ windowseventlog_sink(const windowseventlog_sink&) = delete;
+ windowseventlog_sink& operator=(const windowseventlog_sink&) = delete;
+ windowseventlog_sink(windowseventlog_sink&&) = delete;
+ windowseventlog_sink& operator=(windowseventlog_sink&&) = delete;
+};
+
+} // namespace internal
+} // namespace logging
+} // namespace core
+} // namespace minifi
+} // namespace nifi
+} // namespace apache
+} // namespace org
+
+#endif
diff --git a/libminifi/include/properties/Properties.h
b/libminifi/include/properties/Properties.h
index 420f26c..98bfc76 100644
--- a/libminifi/include/properties/Properties.h
+++ b/libminifi/include/properties/Properties.h
@@ -29,14 +29,6 @@
#include <fstream>
#include "core/logging/Logger.h"
-#ifndef FILE_SEPARATOR
- #ifdef WIN32
- #define FILE_SEPARATOR '\\'
- #else
- #define FILE_SEPARATOR '/'
- #endif
-#endif
-
namespace org {
namespace apache {
@@ -98,8 +90,13 @@ class Properties {
// Parse one line in configure file like key=value
bool parseConfigureFileLine(char *buf, std::string &prop_key, std::string
&prop_value);
- // Load Configure File
+
+ /**
+ * Load configure file
+ * @param fileName path of the configuration file RELATIVE to MINIFI_HOME
set by setHome()
+ */
void loadConfigureFile(const char *fileName);
+
// Set the determined MINIFI_HOME
void setHome(std::string minifiHome) {
minifi_home_ = minifiHome;
diff --git a/libminifi/include/utils/Environment.h
b/libminifi/include/utils/Environment.h
new file mode 100644
index 0000000..bbb7d34
--- /dev/null
+++ b/libminifi/include/utils/Environment.h
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+#ifndef LIBMINIFI_INCLUDE_UTILS_ENVIRONMENT_H_
+#define LIBMINIFI_INCLUDE_UTILS_ENVIRONMENT_H_
+
+#include <functional>
+#include <string>
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+
+/**
+ * A helper class for interacting with the environment in a thread-safe manner.
+ * Note that if environment access occurs outside of this class (in third
parties, or because native setenv/unsetenv/getenv
+ * functions are called natively, and not through this class), then this class
can't guarantee thread safety.
+ */
+class Environment {
+ private:
+ static bool runningAsService_;
+
+ static void accessEnvironment(const std::function<void(void)>& func);
+
+ public:
+ /**
+ * Gets an environment variable using the native OS API
+ * @param name the name of the environment variable
+ * @return a pair consisting of a bool indicating whether the environment
variable is set
+ * and an std::string containing the value of the environemnt variable
+ */
+ static std::pair<bool, std::string> getEnvironmentVariable(const char* name);
+
+ /**
+ * Sets an environment variable using the native OS API
+ * @param name the name of the environment variable
+ * @param value the desired value of the environment variable
+ * @param overwrite if false, will not replace the value of the environment
variable if it is already set
+ * @return true on success. If overwrite is false, will also return true if
the environment variable was not changed
+ */
+ static bool setEnvironmentVariable(const char* name, const char* value, bool
overwrite = true);
+
+ /**
+ * Unsets an environment variable using the native OS API
+ * @param name the name of the environment variable
+ * @return true on success (if the environment variable was successfully
unset, or if it did not exist in the first place)
+ */
+ static bool unsetEnvironmentVariable(const char* name);
+
+ /**
+ * Determines the current working directory
+ * @return current working directory on success, empty string on failure
+ */
+ static std::string getCurrentWorkingDirectory();
+
+ /**
+ * Changes the current working directory
+ * @param directory the directory to change to
+ * @return true on success
+ */
+ static bool setCurrentWorkingDirectory(const char* directory);
+
+ /**
+ * Sets whether the current process is running as a service
+ * @param runningAsService true if the current process is running as a
service
+ */
+ static void setRunningAsService(bool runningAsService);
+
+ /**
+ * Returns the value set by setRunningAsService
+ * @return true if the current process is running as a service
+ */
+ static bool isRunningAsService();
+};
+
+} /* namespace utils */
+} /* namespace minifi */
+} /* namespace nifi */
+} /* namespace apache */
+} /* namespace org */
+
+#endif /* LIBMINIFI_INCLUDE_UTILS_ENVIRONMENT_H_ */
diff --git a/libminifi/include/utils/file/PathUtils.h
b/libminifi/include/utils/file/PathUtils.h
index 12925ce..34f93da 100644
--- a/libminifi/include/utils/file/PathUtils.h
+++ b/libminifi/include/utils/file/PathUtils.h
@@ -35,7 +35,15 @@ namespace PathUtils {
* @param fileName output file name
* @return result of the operation.
*/
-extern bool getFileNameAndPath(const std::string &path, std::string &filePath,
std::string &fileName);
+bool getFileNameAndPath(const std::string &path, std::string &filePath,
std::string &fileName);
+
+/**
+ * Resolves the supplied path to an absolute pathname using the native OS
functions
+ * (realpath(3) on *nix, GetFullPathNameA on Windows)
+ * @param path the name of the file
+ * @return the canonicalized absolute pathname on success, empty string on
failure
+ */
+std::string getFullPath(const std::string& path);
} /* namespace PathUtils */
} /* namespace file */
diff --git a/libminifi/src/Properties.cpp b/libminifi/src/Properties.cpp
index ee2db9e..e42c9e1 100644
--- a/libminifi/src/Properties.cpp
+++ b/libminifi/src/Properties.cpp
@@ -19,6 +19,7 @@
#include <string>
#include "utils/StringUtils.h"
#include "utils/file/FileUtils.h"
+#include "utils/file/PathUtils.h"
#include "core/Core.h"
#include "core/logging/LoggerConfiguration.h"
@@ -120,28 +121,13 @@ void Properties::loadConfigureFile(const char *fileName) {
return;
}
- std::string adjustedFilename = getHome();
- // perform a naive determination if this is a relative path
- if (fileName[0] != utils::file::FileUtils::get_separator()) {
- adjustedFilename += utils::file::FileUtils::get_separator();
- }
-
- adjustedFilename += fileName;
-
- const char *path = NULL;
-#ifndef WIN32
- char full_path[PATH_MAX];
- path = realpath(adjustedFilename.c_str(), full_path);
-#else
- path = adjustedFilename.c_str();
-#endif
- logger_->log_info("Using configuration file to load configuration for %s
from %s (located at %s)", getName().c_str(), fileName, path);
+ properties_file_ =
utils::file::PathUtils::getFullPath(utils::file::FileUtils::concat_path(getHome(),
fileName));
- properties_file_ = path;
+ logger_->log_info("Using configuration file to load configuration for %s
from %s (located at %s)", getName().c_str(), fileName, properties_file_);
- std::ifstream file(path, std::ifstream::in);
+ std::ifstream file(properties_file_, std::ifstream::in);
if (!file.good()) {
- logger_->log_error("load configure file failed %s", path);
+ logger_->log_error("load configure file failed %s", properties_file_);
return;
}
this->clear();
diff --git a/libminifi/src/core/logging/Logger.cpp
b/libminifi/src/core/logging/Logger.cpp
new file mode 100644
index 0000000..617fccb
--- /dev/null
+++ b/libminifi/src/core/logging/Logger.cpp
@@ -0,0 +1,146 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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 "core/logging/Logger.h"
+
+#include <mutex>
+#include <memory>
+#include <sstream>
+#include <iostream>
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace core {
+namespace logging {
+
+
+LoggerControl::LoggerControl()
+ : is_enabled_(true) {
+}
+
+bool LoggerControl::is_enabled() const {
+ return is_enabled_;
+}
+
+void LoggerControl::setEnabled(bool status) {
+ is_enabled_ = status;
+}
+
+
+BaseLogger::~BaseLogger() {
+}
+
+bool BaseLogger::should_log(const LOG_LEVEL &level) {
+ return true;
+}
+
+LogBuilder::LogBuilder(BaseLogger *l, LOG_LEVEL level)
+ : ignore(false),
+ ptr(l),
+ level(level) {
+ if (!l->should_log(level)) {
+ setIgnore();
+ }
+}
+
+LogBuilder::~LogBuilder() {
+ if (!ignore)
+ log_string(level);
+}
+
+void LogBuilder::setIgnore() {
+ ignore = true;
+}
+
+void LogBuilder::log_string(LOG_LEVEL level) {
+ ptr->log_string(level, str.str());
+}
+
+
+bool Logger::should_log(const LOG_LEVEL &level) {
+ if (controller_ && !controller_->is_enabled())
+ return false;
+ spdlog::level::level_enum logger_level = spdlog::level::level_enum::info;
+ switch (level) {
+ case critical:
+ logger_level = spdlog::level::level_enum::critical;
+ break;
+ case err:
+ logger_level = spdlog::level::level_enum::err;
+ break;
+ case info:
+ break;
+ case debug:
+ logger_level = spdlog::level::level_enum::debug;
+ break;
+ case off:
+ logger_level = spdlog::level::level_enum::off;
+ break;
+ case trace:
+ logger_level = spdlog::level::level_enum::trace;
+ break;
+ case warn:
+ logger_level = spdlog::level::level_enum::warn;
+ break;
+ }
+
+ std::lock_guard<std::mutex> lock(mutex_);
+ return delegate_->should_log(logger_level);
+}
+
+void Logger::log_string(LOG_LEVEL level, std::string str) {
+ switch (level) {
+ case critical:
+ log_warn(str.c_str());
+ break;
+ case err:
+ log_error(str.c_str());
+ break;
+ case info:
+ log_info(str.c_str());
+ break;
+ case debug:
+ log_debug(str.c_str());
+ break;
+ case trace:
+ log_trace(str.c_str());
+ break;
+ case warn:
+ log_warn(str.c_str());
+ break;
+ case off:
+ break;
+ }
+}
+
+Logger::Logger(std::shared_ptr<spdlog::logger> delegate,
std::shared_ptr<LoggerControl> controller)
+ : delegate_(delegate), controller_(controller) {
+}
+
+Logger::Logger(std::shared_ptr<spdlog::logger> delegate)
+ : delegate_(delegate), controller_(nullptr) {
+}
+
+} /* namespace logging */
+} /* namespace core */
+} /* namespace minifi */
+} /* namespace nifi */
+} /* namespace apache */
+} /* namespace org */
diff --git a/libminifi/src/core/logging/LoggerConfiguration.cpp
b/libminifi/src/core/logging/LoggerConfiguration.cpp
index 72c53e1..3164d86 100644
--- a/libminifi/src/core/logging/LoggerConfiguration.cpp
+++ b/libminifi/src/core/logging/LoggerConfiguration.cpp
@@ -19,6 +19,7 @@
*/
#include "core/logging/LoggerConfiguration.h"
+
#include <sys/stat.h>
#include <algorithm>
#include <vector>
@@ -31,10 +32,18 @@
#include "utils/StringUtils.h"
#include "utils/ClassUtils.h"
#include "utils/file/FileUtils.h"
+#include "utils/Environment.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_sinks.h"
#include "spdlog/sinks/null_sink.h"
+
+#ifdef WIN32
+#include "core/logging/WindowsEventLogSink.h"
+#else
+#include "spdlog/sinks/syslog_sink.h"
+#endif
+
#ifdef WIN32
#include <direct.h>
#define _WINSOCKAPI_
@@ -175,8 +184,12 @@ std::shared_ptr<internal::LoggerNamespace>
LoggerConfiguration::initialize_names
sink_map[appender_name] =
std::make_shared<spdlog::sinks::rotating_file_sink_mt>(file_name,
max_file_size, max_files);
} else if ("stdout" == appender_type) {
sink_map[appender_name] = spdlog::sinks::stdout_sink_mt::instance();
- } else {
+ } else if ("stderr" == appender_type) {
sink_map[appender_name] = spdlog::sinks::stderr_sink_mt::instance();
+ } else if ("syslog" == appender_type) {
+ sink_map[appender_name] = LoggerConfiguration::create_syslog_sink();
+ } else {
+ sink_map[appender_name] = LoggerConfiguration::create_fallback_sink();
}
}
@@ -281,6 +294,22 @@ std::shared_ptr<spdlog::logger>
LoggerConfiguration::get_logger(std::shared_ptr<
return spdlog::get(name);
}
+std::shared_ptr<spdlog::sinks::sink> LoggerConfiguration::create_syslog_sink()
{
+#ifdef WIN32
+ return std::make_shared<internal::windowseventlog_sink>("ApacheNiFiMiNiFi");
+#else
+ return std::make_shared<spdlog::sinks::syslog_sink>("ApacheNiFiMiNiFi");
+#endif
+}
+
+std::shared_ptr<spdlog::sinks::sink>
LoggerConfiguration::create_fallback_sink() {
+ if (utils::Environment::isRunningAsService()) {
+ return LoggerConfiguration::create_syslog_sink();
+ } else {
+ return spdlog::sinks::stderr_sink_mt::instance();
+ }
+}
+
std::shared_ptr<internal::LoggerNamespace>
LoggerConfiguration::create_default_root() {
std::shared_ptr<internal::LoggerNamespace> result =
std::make_shared<internal::LoggerNamespace>();
result->sinks = std::vector<std::shared_ptr<spdlog::sinks::sink>>();
diff --git a/libminifi/src/core/logging/WindowsEventLogSink.cpp
b/libminifi/src/core/logging/WindowsEventLogSink.cpp
new file mode 100644
index 0000000..d2a0058
--- /dev/null
+++ b/libminifi/src/core/logging/WindowsEventLogSink.cpp
@@ -0,0 +1,95 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+
+#ifdef WIN32
+
+#include "core/logging/WindowsEventLogsink.h"
+
+#include "core/logging/WindowsMessageTextFile.h"
+#include "Exception.h"
+
+#include "spdlog/common.h"
+#include "spdlog/sinks/sink.h"
+#include "spdlog/details/log_msg.h"
+
+#include <string>
+
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace core {
+namespace logging {
+namespace internal {
+
+WORD windowseventlog_sink::type_from_level(const spdlog::details::log_msg&
msg) const {
+ switch (static_cast<int>(msg.level)) {
+ case spdlog::level::trace:
+ case spdlog::level::debug:
+ case spdlog::level::info:
+ return EVENTLOG_INFORMATION_TYPE;
+ case spdlog::level::warn:
+ return EVENTLOG_WARNING_TYPE;
+ case spdlog::level::err:
+ case spdlog::level::critical:
+ return EVENTLOG_ERROR_TYPE;
+ default:
+ return EVENTLOG_ERROR_TYPE;
+ }
+}
+
+void windowseventlog_sink::_sink_it(const spdlog::details::log_msg& msg) {
+ const char* formatted_msg = msg.formatted.c_str();
+ ReportEventA(event_source_,
+ type_from_level(msg) /*wType*/,
+ 0U /*wCategory*/,
+ MSG_DEFAULT /*dwEventID*/,
+ nullptr /* lpUserSid */,
+ 1U /*wNumStrings*/,
+ 0U /*dwDataSize*/,
+ &formatted_msg /*lpStrings*/,
+ nullptr /*lpRawData*/);
+}
+
+void windowseventlog_sink::_flush() {
+}
+
+windowseventlog_sink::windowseventlog_sink(const std::string& source_name /*=
"ApacheNiFiMiNiFi"*/)
+: event_source_(nullptr) {
+ event_source_ = RegisterEventSourceA(nullptr, source_name.c_str());
+ if (event_source_ == nullptr) {
+ throw Exception(GENERAL_EXCEPTION, "Failed to create event source");
+ }
+}
+
+windowseventlog_sink::~windowseventlog_sink() {
+ if (event_source_ != nullptr) {
+ DeregisterEventSource(event_source_);
+ }
+}
+
+} // namespace internal
+} // namespace logging
+} // namespace core
+} // namespace minifi
+} // namespace nifi
+} // namespace apache
+} // namespace org
+
+#endif
diff --git a/libminifi/src/core/logging/WindowsMessageTextFile.mc
b/libminifi/src/core/logging/WindowsMessageTextFile.mc
new file mode 100644
index 0000000..7f09398
--- /dev/null
+++ b/libminifi/src/core/logging/WindowsMessageTextFile.mc
@@ -0,0 +1,24 @@
+;/**
+; * Licensed to the Apache Software Foundation (ASF) under one or more
+; * contributor license agreements. See the NOTICE file distributed with
+; * this work for additional information regarding copyright ownership.
+; * The ASF 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.
+; */
+
+MessageIdTypedef=DWORD
+
+MessageId=0x1
+SymbolicName=MSG_DEFAULT
+Language=English
+%1
+.
diff --git a/libminifi/src/utils/Environment.cpp
b/libminifi/src/utils/Environment.cpp
new file mode 100644
index 0000000..de72dea
--- /dev/null
+++ b/libminifi/src/utils/Environment.cpp
@@ -0,0 +1,185 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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 "utils/Environment.h"
+
+#ifdef WIN32
+#include <Windows.h>
+#else
+#include <cstdlib>
+#include <cerrno>
+#include <unistd.h>
+#endif
+#include <mutex>
+#include <vector>
+#include <iostream>
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace utils {
+
+bool Environment::runningAsService_(false);
+
+void Environment::accessEnvironment(const std::function<void(void)>& func) {
+ static std::recursive_mutex environmentMutex;
+ std::lock_guard<std::recursive_mutex> lock(environmentMutex);
+ func();
+}
+
+std::pair<bool, std::string> Environment::getEnvironmentVariable(const char*
name) {
+ bool exists = false;
+ std::string value;
+
+ Environment::accessEnvironment([&exists, &value, name](){
+#ifdef WIN32
+ std::vector<char> buffer(32767U); //
https://docs.microsoft.com/en-gb/windows/win32/api/processenv/nf-processenv-getenvironmentvariablea
+ // GetEnvironmentVariableA does not set last error to 0 on success, so an
error from a pervious API call would influence the GetLastError() later,
+ // so we set the last error to 0 before calling
+ SetLastError(ERROR_SUCCESS);
+ uint32_t ret = GetEnvironmentVariableA(name, buffer.data(), buffer.size());
+ if (ret > 0U) {
+ exists = true;
+ value = std::string(buffer.data(), ret);
+ } else if (GetLastError() == ERROR_SUCCESS) {
+ // Exists, but empty
+ exists = true;
+ }
+#else
+ char* ret = getenv(name);
+ if (ret != nullptr) {
+ exists = true;
+ value = ret;
+ }
+#endif
+ });
+
+ return std::make_pair(exists, std::move(value));
+}
+
+bool Environment::setEnvironmentVariable(const char* name, const char* value,
bool overwrite /*= true*/) {
+ bool success = false;
+
+ Environment::accessEnvironment([&success, name, value, overwrite](){
+#ifdef WIN32
+ if (!overwrite && Environment::getEnvironmentVariable(name).first) {
+ success = true;
+ } else {
+ success = SetEnvironmentVariableA(name, value);
+ }
+#else
+ int ret = setenv(name, value, static_cast<int>(overwrite));
+ success = ret == 0;
+#endif
+ });
+
+ return success;
+}
+
+bool Environment::unsetEnvironmentVariable(const char* name) {
+ bool success = false;
+
+ Environment::accessEnvironment([&success, name](){
+#ifdef WIN32
+ success = SetEnvironmentVariableA(name, nullptr);
+#else
+ int ret = unsetenv(name);
+ success = ret == 0;
+#endif
+ });
+
+ return success;
+}
+
+std::string Environment::getCurrentWorkingDirectory() {
+ std::string cwd;
+
+ Environment::accessEnvironment([&cwd](){
+#ifdef WIN32
+ uint32_t len = 0U;
+ std::vector<char> buffer;
+ //
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcurrentdirectory
+ // "If the buffer that is pointed to by lpBuffer is not large enough,
+ // the return value specifies the required size of the buffer,
+ // in characters, including the null-terminating character."
+ while (true) {
+ len = GetCurrentDirectoryA(buffer.size(), buffer.data());
+ if (len < buffer.size()) {
+ break;
+ }
+ buffer.resize(len);
+ }
+ if (len > 0U) {
+ cwd = std::string(buffer.data(), len);
+ }
+#else
+ std::vector<char> buffer(1024U);
+ char* path = nullptr;
+ while (true) {
+ path = getcwd(buffer.data(), buffer.size());
+ if (path != nullptr) {
+ cwd = path;
+ break;
+ } else if (errno == ERANGE) {
+ buffer.resize(buffer.size() * 2);
+ } else {
+ break;
+ }
+ }
+#endif
+ });
+
+ return cwd;
+}
+
+bool Environment::setCurrentWorkingDirectory(const char* directory) {
+ bool success = false;
+
+ Environment::accessEnvironment([&success, directory](){
+#ifdef WIN32
+ success = SetCurrentDirectoryA(directory);
+#else
+ int ret = chdir(directory);
+ success = ret == 0;
+#endif
+ });
+
+ return success;
+}
+
+void Environment::setRunningAsService(bool runningAsService) {
+ Environment::accessEnvironment([runningAsService](){
+ runningAsService_ = runningAsService;
+ });
+}
+
+bool Environment::isRunningAsService() {
+ bool runningAsService = false;
+
+ Environment::accessEnvironment([&runningAsService](){
+ runningAsService = runningAsService_;
+ });
+
+ return runningAsService;
+}
+
+} /* namespace utils */
+} /* namespace minifi */
+} /* namespace nifi */
+} /* namespace apache */
+} /* namespace org */
diff --git a/libminifi/src/utils/StringUtils.cpp
b/libminifi/src/utils/StringUtils.cpp
index ce96eec..eb15d27 100644
--- a/libminifi/src/utils/StringUtils.cpp
+++ b/libminifi/src/utils/StringUtils.cpp
@@ -17,9 +17,7 @@
#include "utils/StringUtils.h"
-#ifdef WIN32
-#include <Windows.h>
-#endif
+#include "utils/Environment.h"
namespace org {
namespace apache {
@@ -109,18 +107,10 @@ std::string
StringUtils::replaceEnvironmentVariables(std::string& original_strin
if (env_field.empty()) {
continue;
}
-#ifdef WIN32
- DWORD buffSize = 65535;
- std::vector<char> buffer;
- buffer.resize(buffSize);
- char *strVal = buffer.data();
- GetEnvironmentVariableA(env_field.c_str(), strVal, buffSize);
-#else
- const auto strVal = std::getenv(env_field.c_str());
-#endif
+
std::string env_value;
- if (strVal != nullptr)
- env_value = strVal;
+ std::tie(std::ignore, env_value) =
utils::Environment::getEnvironmentVariable(env_field.c_str());
+
source_string = replaceAll(source_string, env_field_wrapped, env_value);
beg_seq = 0; // restart
} while (beg_seq >= 0);
diff --git a/libminifi/src/utils/file/PathUtils.cpp
b/libminifi/src/utils/file/PathUtils.cpp
index 4982369..6fa95be 100644
--- a/libminifi/src/utils/file/PathUtils.cpp
+++ b/libminifi/src/utils/file/PathUtils.cpp
@@ -18,7 +18,15 @@
#include "utils/file/PathUtils.h"
#include "utils/file/FileUtils.h"
+
#include <iostream>
+#ifdef WIN32
+#include <Windows.h>
+#else
+#include <limits.h>
+#include <stdlib.h>
+#endif
+
namespace org {
namespace apache {
namespace nifi {
@@ -48,6 +56,33 @@ bool PathUtils::getFileNameAndPath(const std::string &path,
std::string &filePat
return true;
}
+std::string PathUtils::getFullPath(const std::string& path) {
+#ifdef WIN32
+ std::vector<char> buffer(MAX_PATH);
+ uint32_t len = 0U;
+ while (true) {
+ len = GetFullPathNameA(path.c_str(), buffer.size(), buffer.data(), nullptr
/*lpFilePart*/);
+ if (len < buffer.size()) {
+ break;
+ }
+ buffer.resize(len);
+ }
+ if (len > 0U) {
+ return std::string(buffer.data(), len);
+ } else {
+ return "";
+ }
+#else
+ std::vector<char> buffer(PATH_MAX);
+ char* res = realpath(path.c_str(), buffer.data());
+ if (res == nullptr) {
+ return "";
+ } else {
+ return res;
+ }
+#endif
+}
+
} /* namespace file */
} /* namespace utils */
} /* namespace minifi */
diff --git a/libminifi/test/TestBase.cpp b/libminifi/test/TestBase.cpp
index 4904682..52cf39a 100644
--- a/libminifi/test/TestBase.cpp
+++ b/libminifi/test/TestBase.cpp
@@ -18,6 +18,21 @@
#include "./TestBase.h"
+#include "spdlog/spdlog.h"
+
+void LogTestController::setLevel(const std::string name,
spdlog::level::level_enum level) {
+ logger_->log_info("Setting log level for %s to %s", name,
spdlog::level::to_str(level));
+ std::string adjusted_name = name;
+ const std::string clazz = "class ";
+ auto haz_clazz = name.find(clazz);
+ if (haz_clazz == 0)
+ adjusted_name = name.substr(clazz.length(), name.length() -
clazz.length());
+ if (config && config->shortenClassNames()) {
+ utils::ClassUtils::shortenClassName(adjusted_name, adjusted_name);
+ }
+ spdlog::get(adjusted_name)->set_level(level);
+}
+
TestPlan::TestPlan(std::shared_ptr<core::ContentRepository> content_repo,
std::shared_ptr<core::Repository> flow_repo, std::shared_ptr<core::Repository>
prov_repo,
const std::shared_ptr<minifi::state::response::FlowVersion>
&flow_version, const std::shared_ptr<minifi::Configure> &configuration)
: configuration_(configuration),
diff --git a/libminifi/test/TestBase.h b/libminifi/test/TestBase.h
index 03f9a1a..7e5416b 100644
--- a/libminifi/test/TestBase.h
+++ b/libminifi/test/TestBase.h
@@ -33,6 +33,7 @@
#include "properties/Properties.h"
#include "core/logging/LoggerConfiguration.h"
#include "utils/Id.h"
+#include "spdlog/common.h"
#include "spdlog/sinks/ostream_sink.h"
#include "spdlog/sinks/dist_sink.h"
#include "unit/ProvenanceTestHelper.h"
@@ -216,20 +217,8 @@ class LogTestController {
LogTestController(LogTestController const&);
LogTestController& operator=(LogTestController const&);
- ;
+ void setLevel(const std::string name, spdlog::level::level_enum level);
- void setLevel(const std::string name, spdlog::level::level_enum level) {
- logger_->log_info("Setting log level for %s to %s", name,
spdlog::level::to_str(level));
- std::string adjusted_name = name;
- const std::string clazz = "class ";
- auto haz_clazz = name.find(clazz);
- if (haz_clazz == 0)
- adjusted_name = name.substr(clazz.length(), name.length() -
clazz.length());
- if (config && config->shortenClassNames()) {
- utils::ClassUtils::shortenClassName(adjusted_name, adjusted_name);
- }
- spdlog::get(adjusted_name)->set_level(level);
- }
std::shared_ptr<logging::LoggerProperties> my_properties_;
std::unique_ptr<logging::LoggerConfiguration> config;
std::set<std::string> modified_loggers;
diff --git a/libminifi/test/unit/EnvironmentUtilsTests.cpp
b/libminifi/test/unit/EnvironmentUtilsTests.cpp
new file mode 100644
index 0000000..fda9a90
--- /dev/null
+++ b/libminifi/test/unit/EnvironmentUtilsTests.cpp
@@ -0,0 +1,154 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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 "../TestBase.h"
+#include "utils/Environment.h"
+#include "utils/file/PathUtils.h"
+
+#include <thread>
+#include <random>
+#include <string>
+#include <cstdint>
+#include <vector>
+
+TEST_CASE("getenv already existing", "[getenv]") {
+ auto res = utils::Environment::getEnvironmentVariable("PATH");
+ REQUIRE(true == res.first);
+ REQUIRE(0 < res.second.length());
+}
+
+TEST_CASE("getenv not existing", "[getenv]") {
+ auto res = utils::Environment::getEnvironmentVariable("GETENV1");
+ REQUIRE(false == res.first);
+ REQUIRE("" == res.second);
+}
+
+TEST_CASE("getenv empty existing", "[getenv]") {
+ REQUIRE(true == utils::Environment::setEnvironmentVariable("GETENV2", ""));
+ auto res = utils::Environment::getEnvironmentVariable("GETENV2");
+ REQUIRE(true == res.first);
+ REQUIRE("" == res.second);
+}
+
+TEST_CASE("setenv not existing overwrite", "[setenv]") {
+ REQUIRE(true == utils::Environment::setEnvironmentVariable("SETENV1",
"test"));
+ auto res = utils::Environment::getEnvironmentVariable("SETENV1");
+ REQUIRE(true == res.first);
+ REQUIRE("test" == res.second);
+}
+
+TEST_CASE("setenv existing overwrite", "[setenv]") {
+ REQUIRE(true == utils::Environment::setEnvironmentVariable("SETENV2",
"test"));
+ REQUIRE(true == utils::Environment::setEnvironmentVariable("SETENV2",
"test2"));
+ auto res = utils::Environment::getEnvironmentVariable("SETENV2");
+ REQUIRE(true == res.first);
+ REQUIRE("test2" == res.second);
+}
+
+TEST_CASE("setenv not existing no overwrite", "[setenv]") {
+ REQUIRE(true == utils::Environment::setEnvironmentVariable("SETENV3",
"test", false /*overwrite*/));
+ auto res = utils::Environment::getEnvironmentVariable("SETENV3");
+ REQUIRE(true == res.first);
+ REQUIRE("test" == res.second);
+}
+
+TEST_CASE("setenv existing no overwrite", "[setenv]") {
+ REQUIRE(true == utils::Environment::setEnvironmentVariable("SETENV4",
"test"));
+ REQUIRE(true == utils::Environment::setEnvironmentVariable("SETENV4",
"test2", false /*overwrite*/));
+ auto res = utils::Environment::getEnvironmentVariable("SETENV4");
+ REQUIRE(true == res.first);
+ REQUIRE("test" == res.second);
+}
+
+TEST_CASE("unsetenv not existing", "[unsetenv]") {
+ REQUIRE(false ==
utils::Environment::getEnvironmentVariable("UNSETENV1").first);
+ REQUIRE(true == utils::Environment::unsetEnvironmentVariable("UNSETENV1"));
+ REQUIRE(false ==
utils::Environment::getEnvironmentVariable("UNSETENV1").first);
+}
+
+TEST_CASE("unsetenv existing", "[unsetenv]") {
+ REQUIRE(true == utils::Environment::setEnvironmentVariable("UNSETENV2",
"test"));
+ REQUIRE(true ==
utils::Environment::getEnvironmentVariable("UNSETENV2").first);
+ REQUIRE(true == utils::Environment::unsetEnvironmentVariable("UNSETENV2"));
+ REQUIRE(false ==
utils::Environment::getEnvironmentVariable("UNSETENV2").first);
+}
+
+TEST_CASE("multithreaded environment manipulation",
"[getenv][setenv][unsetenv]") {
+ std::vector<std::thread> threads;
+ for (size_t i = 0U; i < 16U; i++) {
+ threads.emplace_back([](){
+ std::mt19937 gen(std::random_device { }());
+ for (size_t i = 0U; i < 10240U; i++) {
+ const uint8_t env_num = gen() % 8;
+ const std::string env_name = "GETSETUNSETENV" +
std::to_string(env_num);
+ const uint8_t operation = gen() % 3;
+ switch (operation) {
+ case 0: {
+ auto res =
utils::Environment::getEnvironmentVariable(env_name.c_str());
+ break;
+ }
+ case 1: {
+ const size_t value_len = gen() % 256;
+ std::vector<char> value(value_len + 1, '\0');
+ std::generate_n(value.begin(), value_len, [&]() -> char {
+ return 'A' + gen() % static_cast<uint8_t>('Z' - 'A');
+ });
+ const bool overwrite = gen() % 2;
+ utils::Environment::setEnvironmentVariable(env_name.c_str(),
value.data(), overwrite);
+ break;
+ }
+ case 2: {
+ utils::Environment::unsetEnvironmentVariable(env_name.c_str());
+ break;
+ }
+ }
+ }
+ });
+ }
+ for (auto& thread : threads) {
+ thread.join();
+ }
+ for (size_t i = 0U; i < 8U; i++) {
+ const std::string env_name = "GETSETUNSETENV" + std::to_string(i);
+ bool isset = false;
+ std::string value;
+ std::tie(isset, value) =
utils::Environment::getEnvironmentVariable(env_name.c_str());
+ if (isset) {
+ std::cerr << env_name << " is set to " << value << std::endl;
+ } else {
+ std::cerr << env_name << " is not set" << std::endl;
+ }
+ }
+}
+
+TEST_CASE("getcwd", "[getcwd]") {
+ const std::string cwd = utils::Environment::getCurrentWorkingDirectory();
+ std::cerr << "cwd is " << cwd << std::endl;
+ REQUIRE(false == cwd.empty());
+}
+
+TEST_CASE("setcwd", "[setcwd]") {
+ TestController testController;
+ const std::string cwd = utils::Environment::getCurrentWorkingDirectory();
+ char format[] = "/tmp/envtest.XXXXXX";
+ const std::string tempDir =
utils::file::PathUtils::getFullPath(testController.createTempDirectory(format));
+ REQUIRE(true ==
utils::Environment::setCurrentWorkingDirectory(tempDir.c_str()));
+ REQUIRE(tempDir == utils::Environment::getCurrentWorkingDirectory());
+ REQUIRE(true == utils::Environment::setCurrentWorkingDirectory(cwd.c_str()));
+ REQUIRE(cwd == utils::Environment::getCurrentWorkingDirectory());
+}
diff --git a/libminifi/test/unit/FileUtilsTests.cpp
b/libminifi/test/unit/FileUtilsTests.cpp
index d2a4b9c..83c4e98 100644
--- a/libminifi/test/unit/FileUtilsTests.cpp
+++ b/libminifi/test/unit/FileUtilsTests.cpp
@@ -24,6 +24,8 @@
#include "core/Core.h"
#include "utils/file/FileUtils.h"
#include "utils/file/PathUtils.h"
+#include "utils/ScopeGuard.h"
+#include "utils/Environment.h"
using org::apache::nifi::minifi::utils::file::FileUtils;
@@ -146,3 +148,33 @@ TEST_CASE("TestFileUtils::create_dir", "[TestCreateDir]") {
REQUIRE(FileUtils::create_dir(test_dir_path) == 0); // Dir already exists,
success should be returned
REQUIRE(FileUtils::delete_dir(test_dir_path) == 0); // Delete should be
successful as welll
}
+
+TEST_CASE("TestFileUtils::getFullPath", "[TestGetFullPath]") {
+ TestController testController;
+
+ char format[] = "/tmp/gt.XXXXXX";
+ const std::string tempDir =
utils::file::PathUtils::getFullPath(testController.createTempDirectory(format));
+
+ const std::string cwd = utils::Environment::getCurrentWorkingDirectory();
+
+ REQUIRE(utils::Environment::setCurrentWorkingDirectory(tempDir.c_str()));
+ utils::ScopeGuard cwdGuard([&cwd]() {
+ utils::Environment::setCurrentWorkingDirectory(cwd.c_str());
+ });
+
+ const std::string tempDir1 = utils::file::FileUtils::concat_path(tempDir,
"test1");
+ const std::string tempDir2 = utils::file::FileUtils::concat_path(tempDir,
"test2");
+ REQUIRE(0 == utils::file::FileUtils::create_dir(tempDir1));
+ REQUIRE(0 == utils::file::FileUtils::create_dir(tempDir2));
+
+ REQUIRE(tempDir1 == utils::file::PathUtils::getFullPath(tempDir1));
+ REQUIRE(tempDir1 == utils::file::PathUtils::getFullPath("test1"));
+ REQUIRE(tempDir1 == utils::file::PathUtils::getFullPath("./test1"));
+ REQUIRE(tempDir1 == utils::file::PathUtils::getFullPath("././test1"));
+ REQUIRE(tempDir1 == utils::file::PathUtils::getFullPath("./test2/../test1"));
+#ifdef WIN32
+ REQUIRE(tempDir1 == utils::file::PathUtils::getFullPath(".\\test1"));
+ REQUIRE(tempDir1 == utils::file::PathUtils::getFullPath(".\\.\\test1"));
+ REQUIRE(tempDir1 ==
utils::file::PathUtils::getFullPath(".\\test2\\..\\test1"));
+#endif
+}
diff --git a/libminifi/test/unit/StringUtilsTests.cpp
b/libminifi/test/unit/StringUtilsTests.cpp
index e71b00c..de43029 100644
--- a/libminifi/test/unit/StringUtilsTests.cpp
+++ b/libminifi/test/unit/StringUtilsTests.cpp
@@ -26,15 +26,10 @@
#include "../TestBase.h"
#include "core/Core.h"
#include "utils/StringUtils.h"
+#include "utils/Environment.h"
using org::apache::nifi::minifi::utils::StringUtils;
-#ifdef WIN32
-void setenv(std::string var, std::string value, int val) {
- _putenv_s(var.c_str(), value.c_str());
-}
-#endif
-
TEST_CASE("TestStringUtils::split", "[test split no delimiter]") {
std::vector<std::string> expected = { "hello" };
REQUIRE(expected == StringUtils::split("hello", ","));
@@ -59,7 +54,7 @@ TEST_CASE("TestStringUtils::testEnv1", "[test split
classname]") {
std::string test_string = "hello world ${blahblahnamenamenotexist}";
- setenv("blahblahnamenamenotexist", "computer", 0);
+ utils::Environment::setEnvironmentVariable("blahblahnamenamenotexist",
"computer", 0);
std::string expected = "hello world computer";
@@ -69,7 +64,7 @@ TEST_CASE("TestStringUtils::testEnv1", "[test split
classname]") {
TEST_CASE("TestStringUtils::testEnv2", "[test split classname]") {
std::string test_string = "hello world ${blahblahnamenamenotexist";
- setenv("blahblahnamenamenotexist", "computer", 0);
+ utils::Environment::setEnvironmentVariable("blahblahnamenamenotexist",
"computer");
std::string expected = "hello world ${blahblahnamenamenotexist";
@@ -79,7 +74,7 @@ TEST_CASE("TestStringUtils::testEnv2", "[test split
classname]") {
TEST_CASE("TestStringUtils::testEnv3", "[test split classname]") {
std::string test_string = "hello world $${blahblahnamenamenotexist}";
- setenv("blahblahnamenamenotexist", "computer", 0);
+ utils::Environment::setEnvironmentVariable("blahblahnamenamenotexist",
"computer");
std::string expected = "hello world $computer";
@@ -89,7 +84,7 @@ TEST_CASE("TestStringUtils::testEnv3", "[test split
classname]") {
TEST_CASE("TestStringUtils::testEnv4", "[test split classname]") {
std::string test_string = "hello world \\${blahblahnamenamenotexist}";
- setenv("blahblahnamenamenotexist", "computer", 0);
+ utils::Environment::setEnvironmentVariable("blahblahnamenamenotexist",
"computer");
std::string expected = "hello world ${blahblahnamenamenotexist}";
@@ -97,7 +92,7 @@ TEST_CASE("TestStringUtils::testEnv4", "[test split
classname]") {
}
TEST_CASE("TestStringUtils::testEnv5", "[test split classname]") {
- // can't use blahblahnamenamenotexist because the setenv in other functions
may have already set it
+ // can't use blahblahnamenamenotexist because the
utils::Environment::setEnvironmentVariable in other functions may have already
set it
std::string test_string = "hello world ${blahblahnamenamenotexist2}";
std::string expected = "hello world ";
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index ef0eaf3..2d6a624 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -54,7 +54,12 @@ endif()
endif()
-add_executable(minifiexe MiNiFiMain.cpp MiNiFiWindowsService.cpp AgentDocs.cpp)
+set(MINIFIEXE_SOURCES MiNiFiMain.cpp MainHelper.cpp MiNiFiWindowsService.cpp
AgentDocs.cpp)
+if(WIN32)
+
set_source_files_properties("${CMAKE_BINARY_DIR}/libminifi/src/core/logging/WindowsMessageTextFile.rc"
PROPERTIES GENERATED TRUE)
+ list(APPEND MINIFIEXE_SOURCES
"${CMAKE_BINARY_DIR}/libminifi/src/core/logging/WindowsMessageTextFile.rc")
+endif()
+add_executable(minifiexe ${MINIFIEXE_SOURCES})
if (NOT USE_SHARED_LIBS)
if (LIBC_STATIC)
diff --git a/main/MainHelper.cpp b/main/MainHelper.cpp
new file mode 100644
index 0000000..e719ee7
--- /dev/null
+++ b/main/MainHelper.cpp
@@ -0,0 +1,172 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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 "MainHelper.h"
+
+#include "utils/Environment.h"
+#include "utils/StringUtils.h"
+#include "utils/file/FileUtils.h"
+
+#ifdef WIN32
+FILE* __cdecl _imp____iob_func()
+{
+ struct _iobuf_VS2012 { // ...\Microsoft Visual Studio
11.0\VC\include\stdio.h #56
+ char *_ptr;
+ int _cnt;
+ char *_base;
+ int _flag;
+ int _file;
+ int _charbuf;
+ int _bufsiz;
+ char *_tmpfname;
+ };
+ // VS2015 has FILE = struct {void* _Placeholder}
+
+ static struct _iobuf_VS2012 bufs[3];
+ static char initialized = 0;
+
+ if (!initialized) {
+ bufs[0]._ptr = (char*)stdin->_Placeholder;
+ bufs[1]._ptr = (char*)stdout->_Placeholder;
+ bufs[2]._ptr = (char*)stderr->_Placeholder;
+ initialized = 1;
+ }
+
+ return (FILE*)&bufs;
+}
+
+FILE* __cdecl __imp___iob_func()
+{
+ struct _iobuf_VS2012 { // ...\Microsoft Visual Studio
11.0\VC\include\stdio.h #56
+ char *_ptr;
+ int _cnt;
+ char *_base;
+ int _flag;
+ int _file;
+ int _charbuf;
+ int _bufsiz;
+ char *_tmpfname;
+};
+ // VS2015 has FILE = struct {void* _Placeholder}
+
+ static struct _iobuf_VS2012 bufs[3];
+ static char initialized = 0;
+
+ if (!initialized) {
+ bufs[0]._ptr = (char*)stdin->_Placeholder;
+ bufs[1]._ptr = (char*)stdout->_Placeholder;
+ bufs[2]._ptr = (char*)stderr->_Placeholder;
+ initialized = 1;
+ }
+
+ return (FILE*)&bufs;
+}
+
+#endif
+
+bool validHome(const std::string &home_path) {
+ struct stat stat_result { };
+ const std::string properties_file_path =
utils::file::FileUtils::concat_path(home_path, DEFAULT_NIFI_PROPERTIES_FILE);
+ return stat(properties_file_path.c_str(), &stat_result) == 0;
+}
+
+void setSyslogLogger() {
+ std::shared_ptr<logging::LoggerProperties> service_logger =
std::make_shared<logging::LoggerProperties>();
+ service_logger->set("appender.syslog", "syslog");
+ service_logger->set("logger.root", "INFO,syslog");
+ logging::LoggerConfiguration::getConfiguration().initialize(service_logger);
+}
+
+std::string determineMinifiHome(const std::shared_ptr<logging::Logger>&
logger){
+ /* Try to determine MINIFI_HOME */
+ std::string minifiHome = [&logger]() -> std::string {
+ /* If MINIFI_HOME is set as an environment variable, we will use that */
+ bool minifiHomeSet = false;
+ std::string minifiHome;
+ std::tie(minifiHomeSet, minifiHome) =
utils::Environment::getEnvironmentVariable(MINIFI_HOME_ENV_KEY);
+ if (minifiHomeSet) {
+ logger->log_info("Found " MINIFI_HOME_ENV_KEY "=%s in environment",
minifiHome);
+ return minifiHome;
+ } else {
+ logger->log_info(MINIFI_HOME_ENV_KEY " is not set; trying to infer it");
+ }
+
+ /* Try to determine MINIFI_HOME relative to the location of the minifi
executable */
+ std::string executablePath = utils::file::FileUtils::get_executable_path();
+ if (executablePath.empty()) {
+ logger->log_error("Failed to determine location of the minifi
executable");
+ } else {
+ std::string minifiPath, minifiFileName;
+ std::tie(minifiPath, minifiFileName) =
minifi::utils::file::FileUtils::split_path(executablePath);
+ logger->log_info("Inferred " MINIFI_HOME_ENV_KEY "=%s based on the
minifi executable location %s", minifiPath, executablePath);
+ return minifiPath;
+ }
+
+#ifndef WIN32
+ /* Try to determine MINIFI_HOME relative to the current working directory
*/
+ std::string cwd = utils::Environment::getCurrentWorkingDirectory();
+ if (cwd.empty()) {
+ logger->log_error("Failed to determine current working directory");
+ } else {
+ logger->log_info("Inferred " MINIFI_HOME_ENV_KEY "=%s based on the
current working directory %s", cwd, cwd);
+ return cwd;
+ }
+#endif
+
+ return "";
+ }();
+
+ if (minifiHome.empty()) {
+ logger->log_error("No " MINIFI_HOME_ENV_KEY " could be inferred. "
+ "Please set " MINIFI_HOME_ENV_KEY " or run minifi from a
valid location.");
+ return "";
+ }
+
+ /* Verify that MINIFI_HOME is valid */
+ bool minifiHomeValid = false;
+ if (validHome(minifiHome)) {
+ minifiHomeValid = true;
+ } else {
+ logger->log_info("%s is not a valid " MINIFI_HOME_ENV_KEY ", because there
is no " DEFAULT_NIFI_PROPERTIES_FILE " file in it.", minifiHome);
+
+ std::string minifiHomeWithoutBin, binDir;
+ std::tie(minifiHomeWithoutBin, binDir) =
minifi::utils::file::FileUtils::split_path(minifiHome);
+ if (minifiHomeWithoutBin != "" && (binDir == "bin" || binDir ==
std::string("bin") + minifi::utils::file::FileUtils::get_separator())) {
+ if (validHome(minifiHomeWithoutBin)) {
+ logger->log_info("%s is a valid " MINIFI_HOME_ENV_KEY ", falling back
to it.", minifiHomeWithoutBin);
+ minifiHomeValid = true;
+ minifiHome = std::move(minifiHomeWithoutBin);
+ } else {
+ logger->log_info("%s is not a valid " MINIFI_HOME_ENV_KEY ", because
there is no " DEFAULT_NIFI_PROPERTIES_FILE " file in it.",
minifiHomeWithoutBin);
+ }
+ }
+ }
+
+ /* Fail if not */
+ if (!minifiHomeValid) {
+ logger->log_error("Cannot find a valid " MINIFI_HOME_ENV_KEY " containing
a " DEFAULT_NIFI_PROPERTIES_FILE " file in it. "
+ "Please set " MINIFI_HOME_ENV_KEY " or run minifi from a
valid location.");
+ return "";
+ }
+
+ /* Set the valid MINIFI_HOME in our environment */
+ logger->log_info("Using " MINIFI_HOME_ENV_KEY "=%s", minifiHome);
+ utils::Environment::setEnvironmentVariable(MINIFI_HOME_ENV_KEY,
minifiHome.c_str());
+
+ return minifiHome;
+}
diff --git a/main/Main.h b/main/MainHelper.h
similarity index 57%
rename from main/Main.h
rename to main/MainHelper.h
index 02bcf3a..4126226 100644
--- a/main/Main.h
+++ b/main/MainHelper.h
@@ -15,77 +15,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef MAIN_MAIN_H_
-#define MAIN_MAIN_H_
+#ifndef MAIN_MAINHELPER_H_
+#define MAIN_MAINHELPER_H_
+#include "core/logging/LoggerConfiguration.h"
+#include "core/logging/Logger.h"
-#ifdef WIN32
-#define FILE_SEPARATOR "\\"
-
+#include <string>
+#ifdef WIN32
extern "C" {
- FILE* __cdecl _imp____iob_func()
- {
- struct _iobuf_VS2012 { // ...\Microsoft Visual Studio
11.0\VC\include\stdio.h #56
- char *_ptr;
- int _cnt;
- char *_base;
- int _flag;
- int _file;
- int _charbuf;
- int _bufsiz;
- char *_tmpfname;
- };
- // VS2015 has FILE = struct {void* _Placeholder}
-
- static struct _iobuf_VS2012 bufs[3];
- static char initialized = 0;
-
- if (!initialized) {
- bufs[0]._ptr = (char*)stdin->_Placeholder;
- bufs[1]._ptr = (char*)stdout->_Placeholder;
- bufs[2]._ptr = (char*)stderr->_Placeholder;
- initialized = 1;
- }
-
- return (FILE*)&bufs;
- }
- FILE* __cdecl __imp___iob_func()
- {
- struct _iobuf_VS2012 { // ...\Microsoft Visual Studio
11.0\VC\include\stdio.h #56
- char *_ptr;
- int _cnt;
- char *_base;
- int _flag;
- int _file;
- int _charbuf;
- int _bufsiz;
- char *_tmpfname;
- };
- // VS2015 has FILE = struct {void* _Placeholder}
-
- static struct _iobuf_VS2012 bufs[3];
- static char initialized = 0;
-
- if (!initialized) {
- bufs[0]._ptr = (char*)stdin->_Placeholder;
- bufs[1]._ptr = (char*)stdout->_Placeholder;
- bufs[2]._ptr = (char*)stderr->_Placeholder;
- initialized = 1;
- }
-
- return (FILE*)&bufs;
-}
-}
+ FILE* __cdecl _imp____iob_func();
-#else
-#ifndef FILE_SEPARATOR
-#define FILE_SEPARATOR "/"
-#endif
+ FILE* __cdecl __imp___iob_func();
+}
#endif
+
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
+
//! Main thread sleep interval 1 second
#define SLEEP_INTERVAL 1
//! Main thread stop wait time
@@ -104,6 +53,7 @@ extern "C" {
#define DEFAULT_LOG_PROPERTIES_FILE "./conf/minifi-log.properties"
#define DEFAULT_UID_PROPERTIES_FILE "./conf/minifi-uid.properties"
#endif
+
//! Define home environment variable
#define MINIFI_HOME_ENV_KEY "MINIFI_HOME"
@@ -125,19 +75,19 @@ extern "C" {
* @param home_path
* @return true if home_path represents a valid MINIFI_HOME
*/
-bool validHome(const std::string &home_path) {
- struct stat stat_result { };
- std::string sep;
- sep += FILE_SEPARATOR;
-#ifdef WIN32
- sep = "";
-#endif
- auto properties_file_path = home_path + sep + DEFAULT_NIFI_PROPERTIES_FILE;
- return (stat(properties_file_path.c_str(), &stat_result) == 0);
-}
+bool validHome(const std::string &home_path);
+/**
+ * Configures the logger to log everything to syslog/Windows Event Log, and
for the minimum log level to INFO
+ */
+void setSyslogLogger();
+/**
+ * Determines the full path of MINIFI_HOME
+ * @return MINIFI_HOME on success, empty string on failure
+ */
+std::string determineMinifiHome(const std::shared_ptr<logging::Logger>&
logger);
-#endif /* MAIN_MAIN_H_ */
+#endif /* MAIN_MAINHELPER_H_ */
diff --git a/main/MiNiFiMain.cpp b/main/MiNiFiMain.cpp
index 8325c51..9b0e671 100644
--- a/main/MiNiFiMain.cpp
+++ b/main/MiNiFiMain.cpp
@@ -31,7 +31,7 @@
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "legacy_stdio_definitions.lib")
#ifdef ENABLE_JNI
- #pragma comment(lib, "jvm.lib")
+ #pragma comment(lib, "jvm.lib")
#endif
#include <direct.h>
@@ -54,9 +54,11 @@
#include "core/ConfigurationFactory.h"
#include "core/RepositoryFactory.h"
#include "utils/file/PathUtils.h"
+#include "utils/file/FileUtils.h"
+#include "utils/Environment.h"
#include "FlowController.h"
#include "AgentDocs.h"
-#include "Main.h"
+#include "MainHelper.h"
// Variables that allow us to avoid a timed wait.
sem_t *running;
@@ -74,15 +76,15 @@ sem_t *running;
#ifdef WIN32
BOOL WINAPI consoleSignalHandler(DWORD signal) {
- if (signal == CTRL_C_EVENT || signal == CTRL_BREAK_EVENT)
- {
-
- sem_post(running);
- if (sem_wait(running) == -1)
- perror("sem_wait");
- }
-
- return TRUE;
+ if (signal == CTRL_C_EVENT || signal == CTRL_BREAK_EVENT)
+ {
+
+ sem_post(running);
+ if (sem_wait(running) == -1)
+ perror("sem_wait");
+ }
+
+ return TRUE;
}
void SignalExitProcess() {
@@ -91,161 +93,121 @@ void SignalExitProcess() {
#endif
void sigHandler(int signal) {
- if (signal == SIGINT || signal == SIGTERM) {
- // avoid stopping the controller here.
- sem_post(running);
- }
+ if (signal == SIGINT || signal == SIGTERM) {
+ // avoid stopping the controller here.
+ sem_post(running);
+ }
}
void dumpDocs(const std::shared_ptr<minifi::Configure> &configuration, const
std::string &dir, std::ostream &out) {
- auto pythoncreator =
core::ClassLoader::getDefaultClassLoader().instantiate("PythonCreator",
"PythonCreator");
- if (nullptr != pythoncreator) {
- pythoncreator->configure(configuration);
- }
+ auto pythoncreator =
core::ClassLoader::getDefaultClassLoader().instantiate("PythonCreator",
"PythonCreator");
+ if (nullptr != pythoncreator) {
+ pythoncreator->configure(configuration);
+ }
- minifi::docs::AgentDocs docsCreator;
+ minifi::docs::AgentDocs docsCreator;
- docsCreator.generate(dir, out);
+ docsCreator.generate(dir, out);
}
int main(int argc, char **argv) {
#ifdef WIN32
- CheckRunAsService();
+ RunAsServiceIfNeeded();
+
+ bool isStartedByService = false;
+ HANDLE terminationEventHandler =
GetTerminationEventHandle(&isStartedByService);
+ if (terminationEventHandler == nullptr) {
+ return -1;
+ }
+
+ utils::Environment::setRunningAsService(isStartedByService);
#endif
- std::shared_ptr<logging::Logger> logger =
logging::LoggerConfiguration::getConfiguration().getLogger("main");
+ if (utils::Environment::isRunningAsService()) {
+ setSyslogLogger();
+ }
+ std::shared_ptr<logging::Logger> logger =
logging::LoggerConfiguration::getConfiguration().getLogger("main");
#ifdef WIN32
- if (!CreateServiceTerminationThread(logger)) {
- return -1;
+ if (isStartedByService) {
+ if (!CreateServiceTerminationThread(logger, terminationEventHandler)) {
+ return -1;
+ }
+ } else {
+ CloseHandle(terminationEventHandler);
}
#endif
- uint16_t stop_wait_time = STOP_WAIT_TIME_MS;
+ uint16_t stop_wait_time = STOP_WAIT_TIME_MS;
- // initialize static functions that were defined apriori
- core::FlowConfiguration::initialize_static_functions();
+ // initialize static functions that were defined apriori
+ core::FlowConfiguration::initialize_static_functions();
- std::string graceful_shutdown_seconds = "";
- std::string prov_repo_class = "provenancerepository";
- std::string flow_repo_class = "flowfilerepository";
- std::string nifi_configuration_class_name = "yamlconfiguration";
- std::string content_repo_class = "filesystemrepository";
+ std::string graceful_shutdown_seconds = "";
+ std::string prov_repo_class = "provenancerepository";
+ std::string flow_repo_class = "flowfilerepository";
+ std::string nifi_configuration_class_name = "yamlconfiguration";
+ std::string content_repo_class = "filesystemrepository";
- running = sem_open("/MiNiFiMain", O_CREAT, 0644, 0);
- if (running == SEM_FAILED || running == 0) {
+ running = sem_open("/MiNiFiMain", O_CREAT, 0644, 0);
+ if (running == SEM_FAILED || running == 0) {
- logger->log_error("could not initialize semaphore");
- perror("initialization failure");
- }
+ logger->log_error("could not initialize semaphore");
+ perror("initialization failure");
+ }
#ifdef WIN32
- if (!SetConsoleCtrlHandler(consoleSignalHandler, TRUE)) {
- logger->log_error("Cannot install signal handler");
- std::cerr << "Cannot install signal handler" << std::endl;
- return 1;
- }
-
- if (signal(SIGINT, sigHandler) == SIG_ERR || signal(SIGTERM,
sigHandler) == SIG_ERR ) {
- std::cerr << "Cannot install signal handler" << std::endl;
- return -1;
- }
-#ifdef SIGBREAK
- if (signal(SIGBREAK, sigHandler) == SIG_ERR) {
- std::cerr << "Cannot install signal handler" << std::endl;
- return -1;
- }
-#endif
-#else
- if (signal(SIGINT, sigHandler) == SIG_ERR || signal(SIGTERM,
sigHandler) == SIG_ERR || signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
- std::cerr << "Cannot install signal handler" << std::endl;
- return -1;
- }
-#endif
- // assumes POSIX compliant environment
- std::string minifiHome;
- if (const char *env_p = std::getenv(MINIFI_HOME_ENV_KEY)) {
- minifiHome = env_p;
- logger->log_info("Using MINIFI_HOME=%s from environment.",
minifiHome);
- }
- else {
- logger->log_info("MINIFI_HOME is not set; determining based on
environment.");
- char *path = nullptr;
- char full_path[PATH_MAX];
-#ifndef WIN32
- path = realpath(argv[0], full_path);
-#else
- path = nullptr;
-#endif
+ if (!SetConsoleCtrlHandler(consoleSignalHandler, TRUE)) {
+ logger->log_error("Cannot install signal handler");
+ return -1;
+ }
- if (path != nullptr) {
- std::string minifiHomePath(path);
- if (minifiHomePath.find_last_of("/\\") !=
std::string::npos) {
- minifiHomePath = minifiHomePath.substr(0,
minifiHomePath.find_last_of("/\\")); //Remove /minifi from path
- minifiHome = minifiHomePath.substr(0,
minifiHomePath.find_last_of("/\\")); //Remove /bin from path
- }
- }
-
- // attempt to use cwd as MINIFI_HOME
- if (minifiHome.empty() || !validHome(minifiHome)) {
- char cwd[PATH_MAX];
-#ifdef WIN32
- _getcwd(cwd, PATH_MAX);
- auto handle = GetModuleHandle(0);
- GetModuleFileNameA(NULL, cwd, sizeof(cwd));
- std::string fullPath = cwd;
- std::string minifiFileName, minifiPath;
-
minifi::utils::file::PathUtils::getFileNameAndPath(fullPath, minifiPath,
minifiFileName);
- if (utils::StringUtils::endsWith(minifiPath, "bin")) {
- minifiHome = minifiPath.substr(0,
minifiPath.size()-3);
- }
- else {
- minifiHome = minifiPath;
- }
-
-#else
- getcwd(cwd, PATH_MAX);
- minifiHome = cwd;
+ if (signal(SIGINT, sigHandler) == SIG_ERR || signal(SIGTERM, sigHandler) ==
SIG_ERR ) {
+ logger->log_error("Cannot install signal handler");
+ return -1;
+ }
+#ifdef SIGBREAK
+ if (signal(SIGBREAK, sigHandler) == SIG_ERR) {
+ logger->log_error("Cannot install signal handler");
+ return -1;
+ }
#endif
-
- }
-
-
- logger->log_debug("Setting %s to %s", MINIFI_HOME_ENV_KEY,
minifiHome);
-#ifdef WIN32
- SetEnvironmentVariable(MINIFI_HOME_ENV_KEY, minifiHome.c_str());
#else
- setenv(MINIFI_HOME_ENV_KEY, minifiHome.c_str(), 0);
+ if (signal(SIGINT, sigHandler) == SIG_ERR || signal(SIGTERM, sigHandler) ==
SIG_ERR || signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
+ logger->log_error("Cannot install signal handler");
+ return -1;
+ }
#endif
- }
-
- if (!validHome(minifiHome)) {
- minifiHome = minifiHome.substr(0,
minifiHome.find_last_of("/\\")); //Remove /bin from path
- if (!validHome(minifiHome)) {
- logger->log_error("No valid MINIFI_HOME could be
inferred. "
- "Please set MINIFI_HOME or run minifi from a
valid location. minifiHome is %s", minifiHome);
- return -1;
- }
- }
+ // Determine MINIFI_HOME
+ const std::string minifiHome = determineMinifiHome(logger);
+ if (minifiHome.empty()) {
+ // determineMinifiHome already logged everything we need
+ return -1;
+ }
+ // chdir to MINIFI_HOME
+ if (!utils::Environment::setCurrentWorkingDirectory(minifiHome.c_str())) {
+ logger->log_error("Failed to change working directory to MINIFI_HOME
(%s)", minifiHome);
+ return -1;
+ }
- std::shared_ptr<logging::LoggerProperties> log_properties =
std::make_shared<logging::LoggerProperties>();
- log_properties->setHome(minifiHome);
- log_properties->loadConfigureFile(DEFAULT_LOG_PROPERTIES_FILE);
-
logging::LoggerConfiguration::getConfiguration().initialize(log_properties);
+ std::shared_ptr<logging::LoggerProperties> log_properties =
std::make_shared<logging::LoggerProperties>();
+ log_properties->setHome(minifiHome);
+ log_properties->loadConfigureFile(DEFAULT_LOG_PROPERTIES_FILE);
+ logging::LoggerConfiguration::getConfiguration().initialize(log_properties);
- std::shared_ptr<minifi::Properties> uid_properties =
std::make_shared<minifi::Properties>("UID properties");
- uid_properties->setHome(minifiHome);
- uid_properties->loadConfigureFile(DEFAULT_UID_PROPERTIES_FILE);
- utils::IdGenerator::getIdGenerator()->initialize(uid_properties);
+ std::shared_ptr<minifi::Properties> uid_properties =
std::make_shared<minifi::Properties>("UID properties");
+ uid_properties->setHome(minifiHome);
+ uid_properties->loadConfigureFile(DEFAULT_UID_PROPERTIES_FILE);
+ utils::IdGenerator::getIdGenerator()->initialize(uid_properties);
- // Make a record of minifi home in the configured log file.
- logger->log_info("MINIFI_HOME=%s", minifiHome);
+ // Make a record of minifi home in the configured log file.
+ logger->log_info("MINIFI_HOME=%s", minifiHome);
- std::shared_ptr<minifi::Configure> configure =
std::make_shared<minifi::Configure>();
- configure->setHome(minifiHome);
- configure->loadConfigureFile(DEFAULT_NIFI_PROPERTIES_FILE);
+ std::shared_ptr<minifi::Configure> configure =
std::make_shared<minifi::Configure>();
+ configure->setHome(minifiHome);
+ configure->loadConfigureFile(DEFAULT_NIFI_PROPERTIES_FILE);
if (argc >= 3 && std::string("docs") == argv[1]) {
if (utils::file::FileUtils::create_dir(argv[2]) != 0) {
@@ -270,112 +232,112 @@ int main(int argc, char **argv) {
}
- if (configure->get(minifi::Configure::nifi_graceful_shutdown_seconds,
graceful_shutdown_seconds)) {
- try {
- stop_wait_time = std::stoi(graceful_shutdown_seconds);
- }
- catch (const std::out_of_range &e) {
- logger->log_error("%s is out of range. %s",
minifi::Configure::nifi_graceful_shutdown_seconds, e.what());
- }
- catch (const std::invalid_argument &e) {
- logger->log_error("%s contains an invalid argument set.
%s", minifi::Configure::nifi_graceful_shutdown_seconds, e.what());
- }
- }
- else {
- logger->log_debug("%s not set, defaulting to %d",
minifi::Configure::nifi_graceful_shutdown_seconds,
- STOP_WAIT_TIME_MS);
- }
+ if (configure->get(minifi::Configure::nifi_graceful_shutdown_seconds,
graceful_shutdown_seconds)) {
+ try {
+ stop_wait_time = std::stoi(graceful_shutdown_seconds);
+ }
+ catch (const std::out_of_range &e) {
+ logger->log_error("%s is out of range. %s",
minifi::Configure::nifi_graceful_shutdown_seconds, e.what());
+ }
+ catch (const std::invalid_argument &e) {
+ logger->log_error("%s contains an invalid argument set. %s",
minifi::Configure::nifi_graceful_shutdown_seconds, e.what());
+ }
+ }
+ else {
+ logger->log_debug("%s not set, defaulting to %d",
minifi::Configure::nifi_graceful_shutdown_seconds,
+ STOP_WAIT_TIME_MS);
+ }
-
configure->get(minifi::Configure::nifi_provenance_repository_class_name,
prov_repo_class);
- // Create repos for flow record and provenance
- std::shared_ptr<core::Repository> prov_repo =
core::createRepository(prov_repo_class, true, "provenance");
+ configure->get(minifi::Configure::nifi_provenance_repository_class_name,
prov_repo_class);
+ // Create repos for flow record and provenance
+ std::shared_ptr<core::Repository> prov_repo =
core::createRepository(prov_repo_class, true, "provenance");
- if (!prov_repo->initialize(configure)) {
- std::cerr << "Provenance repository failed to initialize,
exiting.." << std::endl;
- exit(1);
- }
+ if (!prov_repo->initialize(configure)) {
+ logger->log_error("Provenance repository failed to initialize, exiting..");
+ exit(1);
+ }
- configure->get(minifi::Configure::nifi_flow_repository_class_name,
flow_repo_class);
+ configure->get(minifi::Configure::nifi_flow_repository_class_name,
flow_repo_class);
- std::shared_ptr<core::Repository> flow_repo =
core::createRepository(flow_repo_class, true, "flowfile");
+ std::shared_ptr<core::Repository> flow_repo =
core::createRepository(flow_repo_class, true, "flowfile");
- if (!flow_repo->initialize(configure)) {
- std::cerr << "Flow file repository failed to initialize,
exiting.." << std::endl;
- exit(1);
- }
+ if (!flow_repo->initialize(configure)) {
+ logger->log_error("Flow file repository failed to initialize, exiting..");
+ exit(1);
+ }
- configure->get(minifi::Configure::nifi_content_repository_class_name,
content_repo_class);
+ configure->get(minifi::Configure::nifi_content_repository_class_name,
content_repo_class);
- std::shared_ptr<core::ContentRepository> content_repo =
core::createContentRepository(content_repo_class, true, "content");
+ std::shared_ptr<core::ContentRepository> content_repo =
core::createContentRepository(content_repo_class, true, "content");
- if (!content_repo->initialize(configure)) {
- std::cerr << "Content repository failed to initialize,
exiting.." << std::endl;
- exit(1);
- }
+ if (!content_repo->initialize(configure)) {
+ logger->log_error("Content repository failed to initialize, exiting..");
+ exit(1);
+ }
- std::string content_repo_path;
- if
(configure->get(minifi::Configure::nifi_dbcontent_repository_directory_default,
content_repo_path)) {
- std::cout << "setting default dir to " << content_repo_path <<
std::endl;
- minifi::setDefaultDirectory(content_repo_path);
- }
+ std::string content_repo_path;
+ if
(configure->get(minifi::Configure::nifi_dbcontent_repository_directory_default,
content_repo_path)) {
+ logging::LOG_INFO(logger) << "setting default dir to " <<
content_repo_path;
+ minifi::setDefaultDirectory(content_repo_path);
+ }
- configure->get(minifi::Configure::nifi_configuration_class_name,
nifi_configuration_class_name);
+ configure->get(minifi::Configure::nifi_configuration_class_name,
nifi_configuration_class_name);
- std::shared_ptr<minifi::io::StreamFactory> stream_factory =
minifi::io::StreamFactory::getInstance(configure);
+ std::shared_ptr<minifi::io::StreamFactory> stream_factory =
minifi::io::StreamFactory::getInstance(configure);
- std::unique_ptr<core::FlowConfiguration> flow_configuration =
core::createFlowConfiguration(prov_repo, flow_repo, content_repo, configure,
stream_factory, nifi_configuration_class_name);
+ std::unique_ptr<core::FlowConfiguration> flow_configuration =
core::createFlowConfiguration(prov_repo, flow_repo, content_repo, configure,
stream_factory, nifi_configuration_class_name);
- std::shared_ptr<minifi::FlowController> controller =
std::unique_ptr<minifi::FlowController>(
- new minifi::FlowController(prov_repo, flow_repo, configure,
std::move(flow_configuration), content_repo));
+ std::shared_ptr<minifi::FlowController> controller =
std::unique_ptr<minifi::FlowController>(
+ new minifi::FlowController(prov_repo, flow_repo, configure,
std::move(flow_configuration), content_repo));
- logger->log_info("Loading FlowController");
+ logger->log_info("Loading FlowController");
- // Load flow from specified configuration file
- try {
- controller->load();
- }
- catch (std::exception &e) {
- logger->log_error("Failed to load configuration due to
exception: %s", e.what());
- return -1;
- }
- catch (...) {
- logger->log_error("Failed to load configuration due to unknown
exception");
- return -1;
- }
+ // Load flow from specified configuration file
+ try {
+ controller->load();
+ }
+ catch (std::exception &e) {
+ logger->log_error("Failed to load configuration due to exception: %s",
e.what());
+ return -1;
+ }
+ catch (...) {
+ logger->log_error("Failed to load configuration due to unknown exception");
+ return -1;
+ }
- // Start Processing the flow
+ // Start Processing the flow
- controller->start();
- logger->log_info("MiNiFi started");
+ controller->start();
+ logger->log_info("MiNiFi started");
- /**
- * Sem wait provides us the ability to have a controlled
- * yield without the need for a more complex construct and
- * a spin lock
- */
- if (sem_wait(running) == -1)
- perror("sem_wait");
+ /**
+ * Sem wait provides us the ability to have a controlled
+ * yield without the need for a more complex construct and
+ * a spin lock
+ */
+ if (sem_wait(running) == -1)
+ perror("sem_wait");
- if (sem_close(running) == -1)
- perror("sem_close");
+ if (sem_close(running) == -1)
+ perror("sem_close");
- if (sem_unlink("/MiNiFiMain") == -1)
- perror("sem_unlink");
+ if (sem_unlink("/MiNiFiMain") == -1)
+ perror("sem_unlink");
- /**
- * Trigger unload -- wait stop_wait_time
- */
- controller->waitUnload(stop_wait_time);
+ /**
+ * Trigger unload -- wait stop_wait_time
+ */
+ controller->waitUnload(stop_wait_time);
- flow_repo = nullptr;
+ flow_repo = nullptr;
- prov_repo = nullptr;
+ prov_repo = nullptr;
- logger->log_info("MiNiFi exit");
+ logger->log_info("MiNiFi exit");
#ifdef WIN32
- sem_post(running);
+ sem_post(running);
#endif
- return 0;
+ return 0;
}
diff --git a/main/MiNiFiWindowsService.cpp b/main/MiNiFiWindowsService.cpp
index be0e8db..4e243a0 100644
--- a/main/MiNiFiWindowsService.cpp
+++ b/main/MiNiFiWindowsService.cpp
@@ -1,4 +1,21 @@
-#ifdef WIN32
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+
+#ifdef WIN32
#include "MiNiFiWindowsService.h"
@@ -7,6 +24,7 @@
#include <tuple>
#include <tlhelp32.h>
+#include "MainHelper.h"
#include "core/FlowConfiguration.h"
//#define DEBUG_SERVICE
@@ -43,7 +61,7 @@ static void OutputDebug(const char* format, ...) {
va_end(args);
};
-void CheckRunAsService() {
+void RunAsServiceIfNeeded() {
static const int WAIT_TIME_EXE_TERMINATION = 5000;
static const int WAIT_TIME_EXE_RESTART = 60000;
@@ -63,6 +81,8 @@ void CheckRunAsService() {
SERVICE_NAME,
[](DWORD argc, LPTSTR *argv)
{
+ setSyslogLogger();
+
LOG_INFO("ServiceCtrlDispatcher");
s_hEvent = CreateEvent(0, TRUE, FALSE, SERVICE_TERMINATION_EVENT_NAME);
@@ -239,18 +259,21 @@ void CheckRunAsService() {
ExitProcess(0);
}
-bool CreateServiceTerminationThread(std::shared_ptr<logging::Logger> logger) {
+HANDLE GetTerminationEventHandle(bool* isStartedByService) {
+ *isStartedByService = true;
HANDLE hEvent = CreateEvent(0, TRUE, FALSE, SERVICE_TERMINATION_EVENT_NAME);
if (!hEvent) {
- logger->log_error("!CreateEvent lastError %x", GetLastError());
- return false;
+ return nullptr;
}
if (GetLastError() != ERROR_ALREADY_EXISTS) {
- CloseHandle(hEvent);
- return true;
+ *isStartedByService = false;
}
+ return hEvent;
+}
+
+bool CreateServiceTerminationThread(std::shared_ptr<logging::Logger> logger,
HANDLE terminationEventHandle) {
// Get hService and monitor it - if service is terminated, then terminate
current exe, otherwise the exe becomes unmanageable when service is restarted.
auto hService = [&logger]() -> HANDLE {
auto hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@@ -322,18 +345,18 @@ bool
CreateServiceTerminationThread(std::shared_ptr<logging::Logger> logger) {
return false;
using ThreadInfo = std::tuple<std::shared_ptr<logging::Logger>, HANDLE,
HANDLE>;
- auto pThreadInfo = new ThreadInfo(logger, hEvent, hService);
+ auto pThreadInfo = new ThreadInfo(logger, terminationEventHandle, hService);
HANDLE hThread = (HANDLE)_beginthreadex(
0, 0,
[](void* pPar) {
const auto pThreadInfo = static_cast<ThreadInfo*>(pPar);
const auto logger = std::get<0>(*pThreadInfo);
- const auto hEvent = std::get<1>(*pThreadInfo);
+ const auto terminationEventHandle = std::get<1>(*pThreadInfo);
const auto hService = std::get<2>(*pThreadInfo);
delete pThreadInfo;
- HANDLE arHandle[] = { hEvent, hService };
+ HANDLE arHandle[] = { terminationEventHandle, hService };
switch (auto res = WaitForMultipleObjects(_countof(arHandle), arHandle,
FALSE, INFINITE))
{
case WAIT_FAILED:
diff --git a/main/MiNiFiWindowsService.h b/main/MiNiFiWindowsService.h
index ed7e186..85c5429 100644
--- a/main/MiNiFiWindowsService.h
+++ b/main/MiNiFiWindowsService.h
@@ -1,3 +1,20 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+
#pragma once
#ifdef WIN32
@@ -5,7 +22,8 @@
#include <memory>
#include "core/Core.h"
-void CheckRunAsService();
-bool CreateServiceTerminationThread(std::shared_ptr<logging::Logger> logger);
+void RunAsServiceIfNeeded();
+HANDLE GetTerminationEventHandle(bool* isStartedByService);
+bool CreateServiceTerminationThread(std::shared_ptr<logging::Logger> logger,
HANDLE terminationEventHandle);
#endif
diff --git a/msi/WixWin.wsi b/msi/WixWin.wsi
index 6b07237..973aacb 100644
--- a/msi/WixWin.wsi
+++ b/msi/WixWin.wsi
@@ -18,7 +18,8 @@ Licensed to the Apache Software Foundation (ASF) under one or
more
<?include "cpack_variables.wxi"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
- RequiredVersion="3.6.3303.0">
+ RequiredVersion="3.6.3303.0"
+ xmlns:Util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="$(var.CPACK_WIX_PRODUCT_GUID)"
Name="Apache NiFi MiNiFi"
@@ -343,6 +344,9 @@ Licensed to the Apache Software Foundation (ASF) under one
or more
Stop="both"
Remove="uninstall"
Wait="yes" />
+ <Util:EventSource Log="Application"
+ Name="ApacheNiFiMiNiFi"
+ EventMessageFile="[#MiNiFiExe]" />
<Condition><![CDATA[SERVICEACCOUNT="LocalSystem"]]></Condition>
</Component>
<Component Id="minifiServiceNotLocal"
Guid="87658309-0339-425c-8633-f54ffaaa4922">
@@ -371,6 +375,9 @@ Licensed to the Apache Software Foundation (ASF) under one
or more
Stop="both"
Remove="uninstall"
Wait="yes" />
+ <Util:EventSource Log="Application"
+ Name="ApacheNiFiMiNiFi"
+ EventMessageFile="[#MiNiFiExeWithPassword]"
/>
<Condition><![CDATA[SERVICEACCOUNT<>"LocalSystem"]]></Condition>
</Component>
</Directory>
diff --git a/nanofi/include/cxx/Plan.h b/nanofi/include/cxx/Plan.h
index d988810..4d9aec1 100644
--- a/nanofi/include/cxx/Plan.h
+++ b/nanofi/include/cxx/Plan.h
@@ -29,6 +29,7 @@
#include <vector>
#include <set>
#include <map>
+#include <unordered_map>
#include "core/logging/Logger.h"
#include "core/Core.h"
#include "properties/Configure.h"