Search code examples
linuxsyslogrsyslog

Howto act as a syslog receiver?


I want to be a receiver of specific syslog logs. So collect all the syslog messages from one program and push these to the user.

Is there a way I can "subscribe" me at syslog for a unit's log messages?

Other than file watching or so.


Solution

  • In my case it was for rsyslog and can be done via the omuxsock module. omuxsock == "output module unix socket" which is part of rsyslog. This module "writes" the logs to a unix socket, which needs to be created by the receiving program. EDIT: Here is an example for the receiving program:

    #include <sys/un.h>
    #include <sys/socket.h>
    #include <unistd.h>
    #include <iostream>
    #include <sstream>
    #include <vector>
    
    using namespace std;
    
    /*
    this program acts as a receiver for rsyslog messages.
    Just create a .conf file in /etc/rsyslog.d/ with the
    following content:
    
    $ModLoad omuxsock
    $Template MyForwardTemplate,"%PRI%|%TIMESTAMP%|%HOSTNAME%|%syslogtag%|%msg%"
    $OMUxSockSocket /tmp/mysock
    *.* :omuxsock:;MyForwardTemplate
    
    */
    
    vector<string> split(const string &s, char delim) {
        stringstream ss(s);
        string item;
        vector<string> tokens;
        while (getline(ss, item, delim)) {
            tokens.push_back(item);
        }
        return tokens;
    }
    
    int main(int argc, char* argv[])
    {
        const char *mysocketpath = "/tmp/mysock";
        struct sockaddr_un namesock;
        char buffer[512] = { 0 };
        int fd;
        int ret;
    
        namesock.sun_family = AF_UNIX;
        strncpy(namesock.sun_path, (char *)mysocketpath, sizeof(namesock.sun_path));
    
        cerr << "creating the socket ..." << endl;
        fd = ::socket(AF_UNIX, SOCK_DGRAM, 0);
        cerr << "binding it to the socket path ..." << endl;
        ret = ::bind(fd, (struct sockaddr *) &namesock, sizeof(struct sockaddr_un));
        if(ret != 0) {
            cerr << "bind error: " << strerror(errno) << endl;
            ret = 1;
            goto exit;
        }
    
        do {
            memset(buffer, 0, 512);
            ret = ::read(fd, buffer, 512);
            if(ret > 0) {
                string s = buffer;
                vector<string> v = split(buffer, '|');
    
                if(v.size() == 5)
                    cerr << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ", " << v[4] << endl;
                else {
                    for(string s : v) {
                        cerr << s << ", ";
                    }
                    cerr << endl;
                }
            }
        } while(ret > 0);
    
    exit:
        close(fd);
        unlink(mysocketpath);
        return ret;
    }