Skip to content

Commit

Permalink
sample(DBLogger): Save messages from SQL files to an SQL database (wo…
Browse files Browse the repository at this point in the history
…rks with SQLite) (#4750)
  • Loading branch information
matejk committed Nov 13, 2024
1 parent e4d795d commit 93230d6
Showing 1 changed file with 88 additions and 6 deletions.
94 changes: 88 additions & 6 deletions Data/samples/DBLogger/src/DBLogger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@


#include "Poco/Data/SQLChannel.h"
#include "Poco/Data/SQLite/Connector.h"
#include "Poco/Delegate.h"
#include "Poco/DirectoryIterator.h"
#include "Poco/DirectoryWatcher.h"
#include "Poco/FileStream.h"
#include "Poco/Glob.h"
#include "Poco/Thread.h"
#include "Poco/Util/Application.h"
Expand All @@ -24,12 +26,15 @@

#include <iostream>

using namespace Poco::Data::Keywords;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
using Poco::Util::OptionCallback;

using namespace std::string_literals;

class DBLogger: public Application
{
public:
Expand All @@ -49,6 +54,21 @@ class DBLogger: public Application
loadConfiguration(); // load default configuration files, if present
Application::initialize(self);

Poco::Data::SQLite::Connector::registerConnector();

logger().information("conector: %s, cs: %s", _connector, _connectionString);

_dataSession = std::make_shared<Poco::Data::Session>(_connector, _connectionString);

(*_dataSession) << ("DROP TABLE IF EXISTS "s + _tableName), now;
const auto create {
"CREATE TABLE "s + _tableName +
" (Source VARCHAR, Name VARCHAR, ProcessId INTEGER, Thread VARCHAR,"s +
" ThreadId INTEGER, Priority INTEGER, Text VARCHAR, DateTime DATE)"s
};

(*_dataSession) << create, now;

// Initial scan of the directory to pick existing files
scanDirectory();

Expand All @@ -63,7 +83,8 @@ class DBLogger: public Application

// SQL channel to generate SQL files
_sqlChannel = new Poco::Data::SQLChannel();
_sqlChannel->setProperty("directory", _directory);
_sqlChannel->setProperty(Poco::Data::SQLChannel::PROP_DIRECTORY, _directory);
_sqlChannel->setProperty(Poco::Data::SQLChannel::PROP_TABLE, _tableName);

_active = true;
_startTime.update();
Expand All @@ -78,6 +99,7 @@ class DBLogger: public Application
void uninitialize()
{
_sqlSourceThread.join();
_dirWatcher->suspendEvents();

logger().information(
"Created %z messages, processed %z messages in %Ld ms.",
Expand Down Expand Up @@ -112,9 +134,23 @@ class DBLogger: public Application
Option("dir", "d", "directory path to scan for SQL log files")
.required(true)
.repeatable(false)
.argument("filebasename")
.argument("dir")
.callback(OptionCallback<DBLogger>(this, &DBLogger::handleLogDirectory)));

options.addOption(
Option("connector", "c", "database connector")
.required(true)
.repeatable(false)
.argument("connector")
.callback(OptionCallback<DBLogger>(this, &DBLogger::handleDbConnector)));

options.addOption(
Option("constring", "s", "database connection string")
.required(true)
.repeatable(false)
.argument("cstr")
.callback(OptionCallback<DBLogger>(this, &DBLogger::handleDbConnectionString)));

}

void handleHelp(const std::string& name, const std::string& value)
Expand All @@ -124,13 +160,27 @@ class DBLogger: public Application
stopOptionsProcessing();
}

void handleLogDirectory(const std::string& directory, const std::string& value)
void handleLogDirectory(const std::string& name, const std::string& value)
{
if (value.empty())
throw Poco::Util::IncompatibleOptionsException("Expected directory name");
_directory = value;
}

void handleDbConnector(const std::string& name, const std::string& value)
{
if (value.empty())
throw Poco::Util::IncompatibleOptionsException("Expected database connector name");
_connector = value;
}

void handleDbConnectionString(const std::string& name, const std::string& value)
{
if (value.empty())
throw Poco::Util::IncompatibleOptionsException("Expected database connection string");
_connectionString = value;
}

void displayHelp()
{
HelpFormatter helpFormatter(options());
Expand Down Expand Up @@ -173,6 +223,11 @@ class DBLogger: public Application
// TODO: What to do if the file content is modified with correct content after it is added?
// Ignore if empty and process on modified?

if (_dataSession == nullptr || !_dataSession->isGood())
{
return;
}

if (!file.isFile())
{
logger().trace("Not a file: %s", file.absolutePath());
Expand All @@ -191,8 +246,29 @@ class DBLogger: public Application
logger().information("File does not exist: %s", file.absolutePath());
return;
}
f.remove();
++_processed;
try
{
Poco::FileInputStream is(f.absolutePath());
std::stringstream buffer;
buffer << is.rdbuf();
const auto& sql { buffer.str() };
if (!sql.empty())
{
auto& s = (*_dataSession);

s << sql, now;

s.isGood();

f.remove();
++_processed;
}
// TODO: What if sql is empty?
}
catch (const Poco::Exception& e)
{
logger().warning("Failed to process %s: %s", f.absolutePath(), e.displayText());
}
}

void scanDirectory()
Expand Down Expand Up @@ -237,18 +313,24 @@ class DBLogger: public Application

private:
bool _helpRequested;

std::string _directory;
std::string _connector;
std::string _connectionString;
const std::string _tableName{"T_POCO_LOG"};

bool _active {false};

std::size_t _created{0};
std::size_t _processed{0};

Poco::Timestamp _startTime;

std::string _directory;
Poco::Glob _sqlNameGlob;
std::shared_ptr<Poco::DirectoryWatcher> _dirWatcher;
Poco::AutoPtr<Poco::Data::SQLChannel> _sqlChannel;
Poco::Thread _sqlSourceThread;
std::shared_ptr<Poco::Data::Session> _dataSession;
};


Expand Down

0 comments on commit 93230d6

Please sign in to comment.