基于glog使用UDP往以太网发送log

在实际生产中,很多时候需要测试配合查找问题,为了方便测试抓取log,基于glog使用UDP往以太网发送log,只需要wireshark或者一些通用工具就能把log记录下来。本文glog版本是v0.6.0.

在glog上,我们可以通过AddLogSink函数添加自定义的日志输出目标。

GLOG_EXPORT void AddLogSink(LogSink *destination);

该方法需要一个输出参数LogSink,通过继承google::LogSink实现,新类需要实现send函数。send函数即为自定义的发送函数。

virtual void send(google::LogSeverity severity, const char* full_filename,
                      const char* base_filename, int line,
                      const google::LogMessageTime& logmsgtime,
                      const char* message, size_t message_len)

 我在send函数里实现了通过UDP发送log的代码。

#ifndef ETHERNET_LOG_UDP_LOG_SINK_H
#define ETHERNET_LOG_UDP_LOG_SINK_H

#include "glog/logging.h"
#include "udp_log.h"
#include <memory>

class UDPLogSink : public google::LogSink {
public:
    UDPLogSink() {
        udp_log = std::make_unique<UDPLog>();
        udp_log->socket_init();
    }
    UDPLogSink(const std::string& address, uint32_t port) {
        udp_log = std::make_unique<UDPLog>(address, port);
        udp_log->socket_init();
    }
private:
    virtual void send(google::LogSeverity severity, const char* full_filename,
                      const char* base_filename, int line,
                      const google::LogMessageTime& logmsgtime,
                      const char* message, size_t message_len) {
        udp_log->write_log(google::LogSink::ToString(
            severity,
            base_filename,
            line,
            logmsgtime,
            message,
            message_len));
    }

    std::unique_ptr<UDPLog> udp_log{nullptr};
};

#endif //ETHERNET_LOG_UDP_LOG_SINK_H

UDPLog是发送log的实现

udp_log.h

#ifndef ETHERNET_LOG_UDP_LOG_H
#define ETHERNET_LOG_UDP_LOG_H

#include <string>
#include <arpa/inet.h>
#include "mutex"

class UDPLog {

public:
    explicit UDPLog() = default;
    explicit UDPLog(const std::string& address, uint32_t port);
    ~UDPLog();
    int socket_init();
    void write_log(const std::string& log);

private:
    const std::string send_address = "255.255.255.255";
    const uint32_t send_port = 8000;
    int sockfd{0};
    sockaddr_in socket_addr{0};
    std::mutex send_lock;
};


#endif //ETHERNET_LOG_UDP_LOG_H

udp_log.cpp

对于sendto是否需要加锁比较疑惑,查资料有人说要加,有人说不需要,最后为了保险,还是加了锁。

#include "udp_log.h"
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>


UDPLog::~UDPLog() {
    if (sockfd) {
        close(sockfd);
    }
}

void UDPLog::write_log(const std::string &log) {
    std::lock_guard<std::mutex> lock(send_lock);
    sendto(sockfd, log.c_str(), log.size(), 0, (struct sockaddr *)&socket_addr, sizeof(sockaddr));
}

int UDPLog::socket_init() {
    // 创建UDP套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        return sockfd;
    }

    socket_addr.sin_family = AF_INET;
    socket_addr.sin_addr.s_addr = inet_addr(send_address.c_str());
    socket_addr.sin_port = htons(send_port);
    return 0;
}

UDPLog::UDPLog(const std::string &address, uint32_t port) :
send_address(address),
send_port(port) {

}

测试代码main.cpp

#include <iostream>

#include "udp_log/udp_log_sink.h"
#include "glog/logging.h"
#include <thread>
#include <signal.h>

bool loop = true;
void signal_handler(int num) {
    LOG(INFO) << "Program exit, receive signal " << num;
    loop = false;
}

void log_thread(bool& running) {
    while (running) {
        LOG(INFO) << "log thread tid " << gettid();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

int main(int argc, char* argv[]) {

    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);

    FLAGS_log_dir = ".";
    google::InitGoogleLogging(argv[0]);

    UDPLogSink udp_log_sink("192.168.244.1", 8000);
    google::AddLogSink(&udp_log_sink);

    std::thread t1([&]{ log_thread(loop);});
    std::thread t2([&]{ log_thread(loop);});

    uint32_t i = 0;
    while (loop) {
        LOG(INFO) << "hello,world! " << i;
        ++i;
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }

    t1.join();
    t2.join();

    return 0;
}

wireshark测试结果

 网络调试助手

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值