Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ CC=g++
CFLAGS=-std=c++17 -Wall -Wextra -O2 -pthread
LDFLAGS=-lpcap -pthread
TARGET=whatpulse-pcap-service
SOURCES=main.cpp pcapservice.cpp tcpclient.cpp pcapcapturethread.cpp
VERSION=1.0.0
SOURCES=main.cpp pcapservice.cpp tcpclient.cpp pcapcapturethread.cpp logger.cpp
VERSION=1.0.2

# Default target
all: $(TARGET)
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ When WhatPulse runs as an AppImage or in other restricted environments, it may n

### Package Manager Installation (Recommended)

Download the latest packages from the [GitHub Releases page](https://github.com/whatpulse/external-pcap-service/releases/latest).
Download the latest packages from the [GitHub Releases page](https://github.com/whatpulse/linux-external-pcap-service).

Choose the package format for your Linux distribution:

Expand Down Expand Up @@ -45,11 +45,11 @@ For automated downloads, use these commands to get the latest release:

```bash
# Get latest release info
LATEST_URL=$(curl -s https://api.github.com/repos/whatpulse/external-pcap-service/releases/latest | grep "browser_download_url" | grep "deb" | cut -d '"' -f 4)
LATEST_URL=$(curl -s https://api.github.com/repos/whatpulse/linux-external-pcap-service/releases/latest | grep "browser_download_url" | grep "deb" | cut -d '"' -f 4)
wget "$LATEST_URL"

# Or browse all releases:
# https://github.com/whatpulse/external-pcap-service/releases
# https://github.com/whatpulse/linux-external-pcap-service/releases
```

### Build from Source
Expand All @@ -58,7 +58,7 @@ If packages aren't available for your distribution, or you prefer to build from

```bash
# Download and extract source from GitHub releases
# Visit: https://github.com/whatpulse/external-pcap-service/releases
# Visit: https://github.com/whatpulse/linux-external-pcap-service/releases
# Download: whatpulse-pcap-service-VERSION-source.tar.gz

tar xzf whatpulse-pcap-service-*-source.tar.gz
Expand Down
182 changes: 182 additions & 0 deletions logger.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/*
* WhatPulse External PCap Service - Logger Implementation
*
* Copyright (c) 2025 WhatPulse. All rights reserved.
*
* Licensed under CC BY-NC 4.0 with additional terms.
* See LICENSE file for complete terms and conditions.
*
* NOTICE: This software integrates with WhatPulse services. Reverse engineering
* the communication protocol or tampering with data transmission is prohibited.
*
* For licensing questions: [email protected]
*/

#include "logger.h"
#include <iostream>
#include <iomanip>
#include <ctime>

Logger &Logger::getInstance()
{
static Logger instance;
return instance;
}

void Logger::initialize(const std::string &logFile, LogLevel level, bool verbose)
{
m_level = level;
m_verbose = verbose;

// Set performance logging intervals based on verbose mode
if (verbose)
{
m_performanceInterval = m_verbosePerformanceInterval;
}

if (!logFile.empty())
{
m_logFile.close();
m_logFile.open(logFile, std::ios::app);
if (!m_logFile.is_open())
{
std::cerr << "Failed to open log file: " << logFile << std::endl;
return;
}
}

// Initial log entry
std::stringstream ss;
ss << "Logger initialized - Level: " << levelToString(level)
<< ", Verbose: " << (verbose ? "Yes" : "No")
<< ", Performance reports every: " << m_performanceInterval.count() << " seconds";
log(LogLevel::INFO, ss.str());
}

void Logger::log(LogLevel level, const std::string &message)
{
if (level < m_level)
{
return;
}

std::string logEntry = getCurrentTimestamp() + " [" + levelToString(level) + "] " + message;

bool isOpen = m_logFile.is_open();
if (isOpen)
{
m_logFile << logEntry << std::endl;
m_logFile.flush();
}
if(!isOpen || m_verbose)
{
// Fallback to console if file logging fails
if (level >= LogLevel::ERROR)
{
std::cerr << logEntry << std::endl;
}
else
{
std::cout << logEntry << std::endl;
}
}
}

void Logger::logPerformance(const std::string &interfaceName, uint64_t packetCount, uint64_t totalBytes,
double seconds, size_t queueSize, bool isConnected)
{
if (!shouldLogPerformance())
{
return;
}

double mbps = (totalBytes * 8.0) / (seconds * 1024 * 1024);
double pps = packetCount / seconds;

std::stringstream ss;
ss << "PERF [" << interfaceName << "] "
<< "Packets: " << packetCount << " (" << std::fixed << std::setprecision(1) << pps << " pps), "
<< "Rate: " << std::setprecision(2) << mbps << " Mbps, "
<< "Queue: " << queueSize << " packets, "
<< "TCP: " << (isConnected ? "Connected" : "Disconnected");

log(LogLevel::INFO, ss.str());
}

void Logger::logConnectionAttempt(const std::string &host, uint16_t port)
{
std::stringstream ss;
ss << "TCP: Attempting to connect to " << host << ":" << port;
log(LogLevel::INFO, ss.str());
}

void Logger::logConnectionSuccess(const std::string &host, uint16_t port)
{
std::stringstream ss;
ss << "TCP: Successfully connected to " << host << ":" << port;
log(LogLevel::INFO, ss.str());
}

void Logger::logConnectionFailed(const std::string &host, uint16_t port, const std::string &error)
{
std::stringstream ss;
ss << "TCP: Failed to connect to " << host << ":" << port << " - " << error;
log(LogLevel::WARNING, ss.str());
}

void Logger::logDisconnected(const std::string &host, uint16_t port)
{
std::stringstream ss;
ss << "TCP: Disconnected from " << host << ":" << port;
log(LogLevel::INFO, ss.str());
}

void Logger::logSendError(const std::string &error)
{
std::stringstream ss;
ss << "TCP: Send failed - " << error;
log(LogLevel::WARNING, ss.str());
}

std::string Logger::getCurrentTimestamp()
{
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()) %
1000;

std::stringstream ss;
ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
ss << "." << std::setfill('0') << std::setw(3) << milliseconds.count();

return ss.str();
}

std::string Logger::levelToString(LogLevel level)
{
switch (level)
{
case LogLevel::DEBUG:
return "DEBUG";
case LogLevel::INFO:
return "INFO";
case LogLevel::WARNING:
return "WARN";
case LogLevel::ERROR:
return "ERROR";
default:
return "UNKNOWN";
}
}

bool Logger::shouldLogPerformance()
{
auto now = std::chrono::steady_clock::now();
if (now - m_lastPerformanceLog >= m_performanceInterval)
{
m_lastPerformanceLog = now;
return true;
}
return false;
}
79 changes: 79 additions & 0 deletions logger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* WhatPulse External PCap Service - Logger Header
*
* Copyright (c) 2025 WhatPulse. All rights reserved.
*
* Licensed under CC BY-NC 4.0 with additional terms.
* See LICENSE file for complete terms and conditions.
*
* NOTICE: This software integrates with WhatPulse services. Reverse engineering
* the communication protocol or tampering with data transmission is prohibited.
*
* For licensing questions: [email protected]
*/

#pragma once

#include <string>
#include <fstream>
#include <mutex>
#include <sstream>
#include <chrono>
#include <iomanip>

enum class LogLevel
{
DEBUG = 0,
INFO = 1,
WARNING = 2,
ERROR = 3
};

class Logger
{
public:
static Logger &getInstance();

void initialize(const std::string &logFile, LogLevel level = LogLevel::INFO, bool verbose = false);
void setLevel(LogLevel level) { m_level = level; }
void setVerbose(bool verbose) { m_verbose = verbose; }

void log(LogLevel level, const std::string &message);
void debug(const std::string &message) { log(LogLevel::DEBUG, message); }
void info(const std::string &message) { log(LogLevel::INFO, message); }
void warning(const std::string &message) { log(LogLevel::WARNING, message); }
void error(const std::string &message) { log(LogLevel::ERROR, message); }

// Performance logging with throttling
void logPerformance(const std::string &interfaceName, uint64_t packetCount, uint64_t totalBytes,
double seconds, size_t queueSize, bool isConnected);

// Connection state logging
void logConnectionAttempt(const std::string &host, uint16_t port);
void logConnectionSuccess(const std::string &host, uint16_t port);
void logConnectionFailed(const std::string &host, uint16_t port, const std::string &error);
void logDisconnected(const std::string &host, uint16_t port);
void logSendError(const std::string &error);

private:
Logger() = default;
std::string getCurrentTimestamp();
std::string levelToString(LogLevel level);
bool shouldLogPerformance();

std::ofstream m_logFile;
std::mutex m_mutex;
LogLevel m_level = LogLevel::INFO;
bool m_verbose = false;

// Performance logging throttling
std::chrono::steady_clock::time_point m_lastPerformanceLog;
std::chrono::seconds m_performanceInterval{300}; // 5 minutes default
std::chrono::seconds m_verbosePerformanceInterval{10}; // 10 seconds in verbose mode
};

// Convenience macros
#define LOG_DEBUG(msg) Logger::getInstance().debug(msg)
#define LOG_INFO(msg) Logger::getInstance().info(msg)
#define LOG_WARNING(msg) Logger::getInstance().warning(msg)
#define LOG_ERROR(msg) Logger::getInstance().error(msg)
Loading