Event Logging with Streams

Utilizing Redis Streams for Event Logging

Welcome! In this unit, we will explore how to use Redis streams for event logging. This is an important part of our Redis-based backend system project. By the end of this lesson, you will know how to log events and retrieve them using Redis streams. Remember, you've already learned how to manage user data and handle transactions. Now, we're adding another layer to our system by using streams.

What You'll Build

In this unit, we will focus on the following tasks:

  1. Adding entries to a stream: We will log user activities in a Redis stream.
  2. Reading entries from a stream: You will see how to read the logged events from the stream.

Redis streams are like logs where each entry has a unique ID and can store multiple field-value pairs. They're perfect for event logging.

Section 1: Set Up the Redis Connection

We start by including the required headers, creating an Asio I/O context, and opening a Boost.Redis connection. We also define the stream name we will use for logging events.

C++
#include <boost/redis.hpp>
#include <boost/redis/src.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/consign.hpp>
#include <boost/asio/detached.hpp>

#include <iostream>
#include <memory>
#include <string>
#include <vector>

namespace net   = boost::asio;
using boost::redis::connection;
using boost::redis::request;
using boost::redis::response;
using boost::redis::config;
using boost::redis::logger;
using boost::system::error_code;
namespace resp3 = boost::redis::resp3;

int main() {
    net::io_context ioc;
    auto conn = std::make_shared<connection>(ioc);

    // Connect to Redis (localhost:6379 by default)
    conn->async_run(
        config{},
        logger{logger::level::disabled},
        net::consign(net::detached, conn)
    );

    std::string stream_name = "user_activity_stream";

Here, async_run starts the Redis connection in the background. The stream name is "user_activity_stream", which is where our event records will be stored. Each event added to this stream will become part of an ordered log.

Section 2: Add Events and Read Them Back

Next, we create a Redis request that does three things in one pipeline:

  • Adds a login event for Alice
  • Adds a login event for Bob
  • Reads the first two entries from the stream
C++
    // Pipeline:
    // XADD user_activity_stream * event login username alice
    // XADD user_activity_stream * event login username bob
    // XREAD COUNT 2 STREAMS user_activity_stream 0-0
    auto req  = std::make_shared<request>();
    using resp_type = response<
        std::string,                        // XADD alice -> ID
        std::string,                        // XADD bob   -> ID
        std::vector<resp3::node>            // XREAD reply (generic RESP3 tree)
    >;
    auto resp = std::make_shared<resp_type>();

    req->push("XADD", stream_name, "*", "event", "login", "username", "alice");
    req->push("XADD", stream_name, "*", "event", "login", "username", "bob");
    req->push("XREAD", "COUNT", "2", "STREAMS", stream_name, "0-0");

XADD writes a new entry to the stream. The * tells Redis to generate a unique ID automatically for each event. Each entry stores field-value pairs such as:

  • event = login
  • username = alice

Then XREAD reads entries from the stream. The COUNT 2 part limits the result to two entries, and 0-0 means reading from the beginning of the stream. The response type stores two generated IDs as strings and the XREAD result as a generic RESP3 node tree.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal