log4cplus ConsoleAppender does not work in container - c++

I'm trying to containerize my application but I'm having trouble getting log4cplus working. Bottom line up front, logging works when running on the host, but not in the container when I'm logging from long running loops. Its seems like a buffer somewhere is not getting flushed. A minimal example follows.
Additionally, removing the long lived loop removes the issue, presumably log4cplus flushes one last time before tearing down. Lengthening the sleep duration did not seem to help.
main.cpp
#include <iostream>
#include <unistd.h>
#include <log4cplus/logger.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/configurator.h>
#include <log4cplus/initializer.h>
int main(int argc, char **argv)
{
std::cout << "Sanity Check" << std::endl;
auto log4cplus = ::log4cplus::Initializer();
std::string logconfig("log4cplus_configure.ini");
::log4cplus::PropertyConfigurator::doConfigure(logconfig);
auto logger = ::log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("main"));
while (true) {
LOG4CPLUS_ERROR(logger, "Sleeping...");
// std::cout << "cout sleep..." << std::endl; // uncomment to get log messages working
sleep(1);
}
return 0;
}
log4cplus_configure.ini
log4cplus.rootLogger=INFO, MyConsoleAppender
log4cplus.appender.MyConsoleAppender=log4cplus::ConsoleAppender
log4cplus.appender.MyConsoleAppender.layout=log4cplus::PatternLayout
log4cplus.appender.MyConsoleAppender.layout.ConversionPattern=[%-5p][%d] %m%n
Dockerfile
FROM rockylinux:latest
RUN dnf install -y boost-system
COPY ./build/sandbox /
COPY ./log4cplus_configure.ini /
CMD ["/sandbox"]
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
set (CMAKE_CXX_STANDARD 17)
# Project executable and library
add_executable(sandbox main.cpp)
target_link_libraries(sandbox
PUBLIC liblog4cplus.a
PUBLIC pthread
PUBLIC boost_system
)

Not sure why, but adding log4cplus.appender.MyConsoleAppender.ImmediateFlush=true to log4cplus_configure.ini solved my issue.

Related

SQLException 32104 in OCCI

I am trying to use OCCI to connect my program to an oracle database but I am getting an SQLException 32104 when I try the createEnvironment function.
My code:
#include <OpenXLSX.hpp>
#include <occi.h>
#include <string>
using namespace OpenXLSX;
using namespace oracle::occi;
int main() {
std::string user = "";
std::string pass = "";
std::string conn_str = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.2.159)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=test)))";
std::cout << "Initializing Database Connection ......" << std::endl;
try {
Environment* env = Environment::createEnvironment(Environment::DEFAULT);
//Connection *conn = env->createConnection(user, pass ,conn_str);
} catch(SQLException &e) {
std::cout << "Error Message: " << e.getErrorCode() << std::endl;
std::cout << e.getMessage() << std::endl;
}
std::cout << "Initializing Database Connection ......";
std::cout << " OK" << std::endl;
XLDocument doc;
doc.open("Template.xlsx");
auto wks = doc.workbook().worksheet("Extruder Data Log");
int row_number = 4;
char column_letter = 'A';
char column_letter2 = 'A';
std::string loc;
loc = column_letter;
loc += std::to_string(4);
wks.cell(loc).value() = "Hello, OpenXLSX!";
doc.save();
//env->terminateConnection(conn);
//Environment::terminateEnvironment(env);
std::cout << "Program Terminated: Press Enter ...";
std::string wait;
std::cin >> wait;
return 0;
}
I am using CMake to compile:
cmake_minimum_required(VERSION 3.15)
project(Atlas)
set(CMAKE_CXX_STANDARD 17)
# Set the build output location to a common directory
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output)
set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include/lib)
add_subdirectory(OpenXLSX)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/include/OpenXLSX/headers)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/include/OpenXLSX)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/include/OCCI)
link_directories(${CMAKE_PREFIX_PATH})
find_package(OpenXLSX REQUIRED)
find_library(OCCI NAMES oraocci21.lib oci.lib oramysql.lib oraocci21d.lib ociw32.lib)
add_executable(Atlas Atlas.cpp)
target_link_libraries(Atlas OpenXLSX::OpenXLSX)
target_link_libraries(Atlas ${OCCI})
I have the dlls in the output directory where the executable and libraries end up outputting to.
I figure that it should run, but I am getting a Microsoft C++ exception: oracle::occi::SQLException
and on debugging it shows that it is message 32104 which I know means that it cannot get the error.
The Debug window show that it loads the oraocci21.dll but not any of the other OCCI dlls.
If anyone can let me know what I'm doing wrong I would be incredibly grateful since I have scoured the internet trying to figure this out.
EDIT
Figured out this error, I hadn't moved all of the dlls from the instant client. I was only including the dlls that corresponded to the library names.
I included ocijdbc21.dll, orannzsbb.dll, and oraociicus.dll to the folder with my executable and it now runs past the createEnvironment(Environment::DEFAULT) part.
With this edit, though, I am now running into Error 24960 which says that OCI_ATTR_USERNAME is more than length 255 which it is not.
If anyone can help with that please let me know but I hope that anyone else running across this who needs help sees the part about the dlls.
If it helps to answer my question, I am using instant client base 21_3 and sdk 21_3. I am also using MSVC 16 2019 for compilation with C++17 as the version of C++. My Oracle Database is running on 19c and I can connect to it remotely.
So I figured it out.
I was using this command for cmake:
cmake --build . --target ALL_BUILD --config Debug
This release config command should work because I have debugged the program:
cmake --build . --target ALL_BUILD --config Release
For some reason, I can only assume that OCCI did not like my debugger
version or something like that. If someone could please comment on why this happens I would like to learn.

Attaching debugger give me the credentials, removing it and the credentials are empty

I have a problem with the AWS sdk on a Qt app.
I'm getting the STS tokens from Cognito after a click on a QML button.
The function is working perfectly fine and is printing me the token... as long as the debugger is attached [F5]. If I start the project without debugger (green arrow without bug on it) the returned object is empty.
Without the debugger attached I have the following in the aws logs that I don't have otherwise:
[INFO] 2020-09-18 12:33:02.569 CognitoCachingCredentialsProvider [140678610167936] A parent identity was from cognito which is different from the anonymous identity. Swapping that out now.
[INFO] 2020-09-18 12:33:02.569 CognitoCachingCredentialsProvider [140678610167936] Credentials will expire next at 0
Other logs around looks the same, I even have the STS token shown a couples of lines above this one on both cases:
[DEBUG] 2020-09-18 12:33:02.569 CURL [140678610167936] (DataIn) {"Credentials":{"AccessKeyId":"###","Expiration":1.600435982E9,"SecretKey":"###","SessionToken":"##########"},"IdentityId":"<MY_IDENTITY_ID>"}
I have even edited the SDK and added the following logs which resulted in this (with the debugger attached the first line is also getting <MY_IDENTITY_ID> shown).
AWS_LOGSTREAM_INFO("TOTO", "parentIdentityId" << parentIdentityId);
AWS_LOGSTREAM_INFO("TOTO", "m_identityRepository->GetIdentityId() " << m_identityRepository->GetIdentityId()) ;
[INFO] 2020-09-18 12:33:02.569 TOTO [140678610167936] parentIdentityId
[INFO] 2020-09-18 12:33:02.569 TOTO [140678610167936] m_identityRepository->GetIdentityId() <MY_IDENTITY_ID>
Added here https://github.com/aws/aws-sdk-cpp/blob/6d6dcdbfa377393306bf79585f61baea524ac124/aws-cpp-sdk-identity-management/source/auth/CognitoCachingCredentialsProvider.cpp#L52
No commenting the line 56 does not fix my problem.
Attached is my minimal project to reproduce the behavior if you want (You will need to have an AWS setup and an openID provider).
I tried on pure C++ and I get everything even without debugger.
The problem arises when instantiating the QtCoreApplication.
On the base app I tried setting a QTimer::singleShot(100, /*...*/) and I still got the problem.
You can install the aws SDK from here https://github.com/aws/aws-sdk-cpp and if you don't want to install the whole SDK, the project only need a little part of the sdk so add -DBUILD_ONLY="identity-management" to cmake to only build the needed part.
Qt 5.12.5
aws-sdk-cpp on tag: 1.8.42 (Had the same problem from previous patch version and the latest change very often)
Question
What magic attaching the debugger do to allow an application that instanciated a QCoreApplication getting tokens from the aws sdk ?
I am saying it again here: I do not have a DEBUG and a RELEASE build, I just use the arrow vs arrow with a bug on it in qtcreator. As far as I know the environment is the same, just qtcreator attach or not the debugger.
Indeed in release I have the same problem (STS shown when the debugger is attached, empty when not).
Minimal working example
main.cpp (The commented code should do the same as credentials = cognitoAuth.GetAWSCredentials();, and so I have the same behaviour.)
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <aws/cognito-identity/model/GetCredentialsForIdentityRequest.h>
#include <aws/cognito-identity/model/GetIdRequest.h>
#include <aws/core/Aws.h>
#include <aws/identity-management/auth/CognitoCachingCredentialsProvider.h>
#include <aws/identity-management/auth/PersistentCognitoIdentityProvider.h>
Aws::String m_region = Aws::Region::<PICK_YOUR_REGION>;
Aws::String m_providerUrl = "<PROVIDER_URL>";
Aws::String m_accountId = "<ACCOUNT_ID>";
Aws::String m_identityPoolId = "<IDENTITY_POOL_ID>";
Aws::Auth::AWSCredentials getSTS(const std::string idToken) {
const char *persistentFile = "/tmp/aws.identities";
QFile::remove(persistentFile);
Aws::Auth::AWSCredentials credentials;
// Aws::CognitoIdentity::Model::Credentials credentials;
std::shared_ptr<Aws::CognitoIdentity::CognitoIdentityClient> cognitoClient;
Aws::SDKOptions options;
options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace;
Aws::InitAPI(options);
{
Aws::Client::ClientConfiguration config;
config.region = m_region;
cognitoClient =
std::make_shared<Aws::CognitoIdentity::CognitoIdentityClient>(config);
std::shared_ptr<Aws::Auth::PersistentCognitoIdentityProvider_JsonFileImpl>
identityProvider = std::make_shared<
Aws::Auth::PersistentCognitoIdentityProvider_JsonFileImpl>(
m_identityPoolId, m_accountId, persistentFile);
Aws::Map<Aws::String, Aws::Auth::LoginAccessTokens> logins;
Aws::Auth::LoginAccessTokens loginAccessTokens;
loginAccessTokens.accessToken = idToken;
logins[m_providerUrl] = loginAccessTokens;
identityProvider->PersistLogins(logins);
// QThread::sleep(5);
Aws::Auth::CognitoCachingAuthenticatedCredentialsProvider cognitoAuth{
identityProvider, cognitoClient};
///////////////////////////////////////////////////////////////////////////
// Aws::CognitoIdentity::Model::GetIdRequest idRequest;
// idRequest.SetIdentityPoolId(m_identityPoolId.c_str());
// idRequest.AddLogins(m_providerUrl, idToken.c_str());
////idRequest.SetIdentityPoolId((region + ":" + identityPoolId).c_str());
//
// auto idResult = cognitoClient->GetId(idRequest);
// if(!idResult.IsSuccess())
//{
// qCWarning(mqttAwsWebsocket) << "(GetId): " <<
// idResult.GetError().GetExceptionName().c_str() << ":"
// <<
// idResult.GetError().GetMessage().c_str();
// // throw
//}
//
// QThread::sleep(5);
//
// Aws::CognitoIdentity::Model::GetCredentialsForIdentityRequest
// credForIdRequest;
// credForIdRequest.SetIdentityId(idResult.GetResult().GetIdentityId());
// credForIdRequest.AddLogins(m_providerUrl, idToken.c_str());
//
// auto credForIdResult =
// cognitoClient->GetCredentialsForIdentity(credForIdRequest);
// if(!idResult.IsSuccess())
//{
// qCWarning(mqttAwsWebsocket) << "(GetCredentialsForIdentity): "
// <<
// credForIdResult.GetError().GetExceptionName().c_str()
// << ":"
// <<
// credForIdResult.GetError().GetMessage().c_str();
// // throw
//}
//
// qDebug() << "COGNITO STS TOKEN RESULTS";
// qDebug() << "cognitoClient->GetId: " << idResult.IsSuccess();
// qDebug() << "cognitoClient->GetCredentialsForIdentity: " <<
// credForIdResult.IsSuccess(); credentials =
// credForIdResult.GetResult().GetCredentials();
///////////////////////////////////////////////////////////////////////////
// QThread::sleep(5);
credentials = cognitoAuth.GetAWSCredentials();
qDebug() << credentials.IsEmpty() << tries;
qDebug() << credentials.GetAWSAccessKeyId().c_str();
qDebug() << credentials.GetAWSSecretKey().c_str();
qDebug() << credentials.GetSessionToken().c_str();
qDebug() << credentials.IsExpired()
<< credentials.GetExpiration()
.ToLocalTimeString(Aws::Utils::DateFormat::RFC822)
.c_str();
}
Aws::ShutdownAPI(options);
return credentials;
}
int main(int argc, char **argv) {
// Comment just this line and the problem is fixed.
QCoreApplication app(argc, argv);
getSTS("<PAST_OPEN_ID_TOKEN_GOTTEN_FROM_REAL_APP>");
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(aws-sts LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Core)
set(BUILD_SHARED_LIBS ON)
find_package(AWSSDK REQUIRED COMPONENTS identity-management)
add_executable(aws-sts main.cpp)
target_link_libraries(aws-sts PRIVATE
Qt5::Core
${AWSSDK_LINK_LIBRARIES}
)
Update
I simplified the minimal working example since in fact just adding (or commenting ot) QCoreApplication app(argc, argv); is sufficient to reproduce the behavior. I mean just the object creation, no need for it to be a QGuiApplication or start the event loop with app.exec().
It turns out that the aws sdk is using cJSON which, when parsing numbers, may or may not get the local environment for decoding decimal point. But in both cases it will call double strtod(const char *nptr, char **endptr); to translate string to double, in the man page we can read (emphasis mine)
A decimal number consists of a nonempty sequence of decimal digits possibly containing a radix character (decimal point, locale-dependent, usually '.'), optionally followed by a decimal exponent. [...]
Apparently cJSON need this compilation variable to compile on Android.
AWS copied the lib here but did not copied the compilation variable ENABLE_LOCALES which should be enabled by default as stated in the issue linked above.
I am on Ubuntu 18.04, environment in English but dates/number in French (decimal point is ',' here in France).
I am creating an issue on the AWS SDK repo to set the compilation variable ENABLE_LOCALES and on cJSON to discuss and avoid further error like this one.
A potential fix could also be to force the application to use English locales but that is not always possible.

There is not such a file called "SDL2.h"

I run KDE Neon 20.04 and whenever i try to run this command block in Sublime Text i get this error.
#include "SDL2.h"
#include "SDL2_image"
#include <iostream.h>
int main(int argc, char* args[])
{
std::cout << "Yay" << std::endl;
return 0;
}
SDL2.h there is no such file or directory
You have to install SDL development libraries first. You can install it using the command sudo apt-get install libsdl2-dev.
You are also including sdl headers wrong.
This is the correct way.
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

Build and run C++ code during CMake stage rather than build stage

I am writing a custom CMake find module to use a 3rd party library and would like to extract its version string to use with:
find_package_handle_standard_args(MySDK
REQUIRED_VARS LIBRARY INCLUDE
VERSION_VAR VERSION
)
However its version number is not available as text in the header so I have to build a small c++ program to print it to stdout:
#include <MySDK.h>
int main(int argc, const char * argv[]) {
MySDK::Version version = MySDK::getVersion();
std::cout << version.text << "\n";
return 0;
}
I have tried adding to my custom FindMySDK.cmake something like this:
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/version.cpp"
"
#include <MySDK.h>
int main(int argc, const char * argv[]) {
MySDK::Version version = MySDK::getVersion();
std::cout << version.text << \"\\n\";
return 0;
}
"
)
add_executable(MySDKVersion
EXCLUDE_FROM_ALL
"${CMAKE_CURRENT_BINARY_DIR}/version.cpp"
)
target_include_directories(MySDKVersion SYSTEM PRIVATE ${MYSDK_INCLUDE_DIRS})
target_link_libraries(MySDKVersion ${MYSDK_LIBRARIES})
execute_process(COMMAND "$<TARGET_FILE:MySDKVersion>")
But it outputs an empty string. Is there a better way to do this kind of thing?
You need to use the try_run command.
Note, that this won't work when cross-compiling, because when cross-compiling any built binaries are not runnable on the host. However when it's your last option, that's what you use.

libcurl c++ curl_easy_init not working

I just tried setting up curl for the first time using windows + mingw + eclipse juno + curl 7.29. I managed to get it to compile and build fine. I've added the two flags for lcurl and lcurldll.
For some reason though the following does not work:
#include <iostream>
#include <curl.h>
using namespace std;
int main(int argc,char *argv[]) {
cout << "L1" << endl;
CURL *curl;
curl = curl_easy_init();
cout << "L2" << endl;
}
Neither L1 nor L2 will print. If I comment out the easy_init line though it runs fine.
I can't seem to find any similar posts, sorry if this is a dupe. Also, I can't step into anything as it dies as soon as I hit run. I'm sure its something obvious.
Thanks in advance.
Eclipse IDE for C/C++ Developers Version: Juno Service Release 1
Build id: 20120920-0800
curl version: 7.29.0 - SSL enabled
URL: http://curl.haxx.se/gknw.net/7.29.0/dist-w32/curl-7.29.0-devel-mingw32.zip
as for mingw not sure which version I have, I just went to http://sourceforge.net/projects/mingw/files/ and downloaded / installed the latest ver.
In eclipse, under MinGW C++ linker, I have curl and curldll for libraries. In misc I have the static flag - those are the only compiler settings I have changed.
It does work for me, but i just had to add system("PAUSE") at the end since the console close before i can see anything.
here's my code :
#include <curl.h>
#include <iostream>
using namespace std;
int main(void)
{
cout << "L1" << endl;
CURL *curl;
curl = curl_easy_init();
cout << "L2" << endl;
system("PAUSE");
return 0;
}
If you get the message "cannot open include file: 'curl.h': no such file or directory" or something like that, this is because you've missed something in the installation of curl.
It took me a long time to install it.