Skip to content

6. Client Examples

Eneko Gonzalez edited this page Jan 28, 2025 · 5 revisions

ChronoLog provides various clients to interact with its system. Each client has been designed to cater to specific use cases, offering users flexibility and ease of use. Below is a description of the available clients and how they can be utilized effectively.


6.1. Basic Use of the Client API

The Client API is a foundational component of ChronoLog that allows developers to interact directly with the system programmatically. This is ideal for scenarios where a user or application needs to:

  • Write logs to ChronoLog.
  • Perform metadata operations such as creating, acquiring, and releasing Chronicles and Stories.
  • Integrate ChronoLog into custom applications with precise control.

Key Features:

  • Multi-threaded support for concurrent operations.
  • Fine-grained control over ChronoLog functionality.

Example Usage:

Below is a simple example that demonstrates the basic use of the ChronoLog Client API without multithreading. This example provides a step-by-step guide to creating a chronicle, acquiring a story, logging events, and cleaning up resources.

#include <chronolog_client.h>
#include <iostream>
#include <cassert>

int main() {
    // Configuration file path (update this to your configuration file location)
    std::string conf_file_path = "./conf.json";

    // Initialize the ChronoLog client
    ChronoLog::ConfigurationManager confManager(conf_file_path);
    chronolog::Client client(confManager);

    // Connect to the ChronoVisor
    int ret = client.Connect();
    if (ret != chronolog::CL_SUCCESS) {
        std::cerr << "Failed to connect to ChronoVisor. Error code: " << ret << std::endl;
        return -1;
    }

    // Define the chronicle and story names
    std::string chronicle_name = "example_chronicle";
    std::string story_name = "example_story";

    // Create a chronicle
    std::map<std::string, std::string> chronicle_attrs;
    chronicle_attrs.emplace("Priority", "High");
    ret = client.CreateChronicle(chronicle_name, chronicle_attrs, 0);
    if (ret != chronolog::CL_SUCCESS && ret != chronolog::CL_ERR_CHRONICLE_EXISTS) {
        std::cerr << "Failed to create chronicle. Error code: " << ret << std::endl;
        return -1;
    }

    // Acquire a story in the chronicle
    std::map<std::string, std::string> story_attrs;
    auto acquire_ret = client.AcquireStory(chronicle_name, story_name, story_attrs, 0);
    if (acquire_ret.first != chronolog::CL_SUCCESS) {
        std::cerr << "Failed to acquire story. Error code: " << acquire_ret.first << std::endl;
        return -1;
    }

    // Log events to the story
    auto story_handle = acquire_ret.second;
    for (int i = 0; i < 10; ++i) {
        story_handle->log_event("Event " + std::to_string(i));
    }

    // Release the story
    ret = client.ReleaseStory(chronicle_name, story_name);
    if (ret != chronolog::CL_SUCCESS) {
        std::cerr << "Failed to release story. Error code: " << ret << std::endl;
    }

    // Destroy the story
    ret = client.DestroyStory(chronicle_name, story_name);
    if (ret != chronolog::CL_SUCCESS) {
        std::cerr << "Failed to destroy story. Error code: " << ret << std::endl;
    }

    // Destroy the chronicle
    ret = client.DestroyChronicle(chronicle_name);
    if (ret != chronolog::CL_SUCCESS) {
        std::cerr << "Failed to destroy chronicle. Error code: " << ret << std::endl;
    }

    // Disconnect the client
    ret = client.Disconnect();
    if (ret != chronolog::CL_SUCCESS) {
        std::cerr << "Failed to disconnect. Error code: " << ret << std::endl;
    }

    return 0;
}

Advanced Example: Multi-Threaded Test Case

For users interested in testing or deploying advanced use cases, the client_lib_multi_storytellers test demonstrates multi-threaded interactions with ChronoLog. This includes creating chronicles, acquiring and releasing stories, and logging events concurrently across multiple threads.

This test is particularly useful for:

  • Evaluating performance under concurrent workloads.
  • Simulating real-world scenarios with multiple writers.

The full implementation of client_lib_multi_storytellers can be found in the ChronoLog repository.


6.2. Interactive Client Admin

The Interactive Client Admin is a command-line tool that provides an interactive interface for users to manage and operate on ChronoLog deployments. This client is designed for ease of use, allowing real-time interaction with the system.

Key Features:

  • Interactive mode activated using the -i flag.
  • Provides a guided interface for managing Chronicles, Stories, and Events.
  • Outputs detailed configuration and logging information for troubleshooting and monitoring.

Supported Commands:

-c <chronicle_name>         # Create a Chronicle
-a -s <chronicle_name> <story_name>  # Acquire a Story in a Chronicle
-w <event_string>           # Write an Event with a payload
-q -s <chronicle_name> <story_name>  # Release a Story in a Chronicle
-d -s <chronicle_name> <story_name>  # Destroy a Story in a Chronicle
-d -c <chronicle_name>      # Destroy a Chronicle
-disconnect                 # Disconnect from the server

Example Usage:

To run the Interactive Client Admin, execute the following command:

client_admin -i

Once launched, the tool will display the list of available commands. You can then enter commands interactively, such as:

-c my_chronicle
-a -s my_chronicle my_story
-w "This is a test event"
-q -s my_chronicle my_story
-d -s my_chronicle my_story
-d -c my_chronicle
-disconnect

The interactive mode is particularly useful for users who are new to ChronoLog or for debugging and monitoring a live system. Error messages and status outputs are displayed after each command to ensure clear feedback.


6.3. Scripted Client Admin

The Scripted Client Admin extends the functionality of the Interactive Client Admin by enabling automation through scripts. This client is ideal for executing repetitive or predefined tasks without manual intervention.

Key Features:

  • Accepts a list of arguments or script files to perform operations.
  • Automates the creation, acquisition, and management of Chronicles, Stories, and Events.
  • Suitable for running synthetic workloads or batch processing tasks.

Example Script:

Here is an example of a script file (scripted_workload.sh) to automate operations:

# Create a Chronicle and a Story, write events, and clean up
client_admin -c my_chronicle
client_admin -a -s my_chronicle my_story
client_admin -w "Event 1"
client_admin -w "Event 2"
client_admin -q -s my_chronicle my_story
client_admin -d -s my_chronicle my_story
client_admin -d -c my_chronicle

Running the Script:

Execute the script using the -f flag:

client_admin -f scripted_workload.sh

This example demonstrates how to automate the lifecycle of Chronicles and Stories, making the tool ideal for integration into continuous workflows or stress-testing scenarios.

Additional Features:

  • Performance Testing: Use the --perf flag to collect performance metrics for operations.
  • Shared Stories: Use the --shared_story flag to test collaborative access scenarios.

6.4. Python Client

The Python Client is a wrapper around the Client API, designed to enhance usability and extend ChronoLog’s functionality for a broader range of use cases. This client allows users to interact with ChronoLog using Python, making it accessible to data scientists, researchers, and developers who prefer scripting in Python.

Key Features:

  • Simplified API for interacting with ChronoLog.
  • Compatible with popular Python libraries for data processing and analysis.
  • Ideal for prototyping, data analysis, and integration into Python-based pipelines.

Example Usage:

The Python Client is built using the pybind11 library to create Python bindings for the ChronoLog Client API. Below is an example of a Python test script that demonstrates its usage:

import py_chronolog_client

print("Basic test for py_chronolog_client")

# Create ClientPortalServiceConf instance with connection credentials
clientConf = py_chronolog_client.ClientPortalServiceConf("ofi+sockets", "127.0.0.1", 5555, 55)

# Instantiate ChronoLog Client object
client = py_chronolog_client.Client(clientConf)

# Attempt to acquire a story before connecting
attrs = {}
return_tuple = client.AcquireStory("py_chronicle", "my_story", attrs, 1)
print("\nAttempt to acquire story without ChronoVisor connection returns:", return_tuple)

# Connect to ChronoVisor
return_code = client.Connect()
print("\nclient.Connect() call returns:", return_code)

# Create a chronicle
return_code = client.CreateChronicle("py_chronicle", attrs, 1)
print("\nclient.CreateChronicle() returned:", return_code)

# Acquire a story within the chronicle
return_tuple = client.AcquireStory("py_chronicle", "my_story", attrs, 1)
print("\nclient.AcquireStory() returned:", return_tuple)

if return_tuple[0] == 0:
    print("\nAcquired Story = my_story within Chronicle = py_chronicle")

    # Log events to the story
    print("\nLogging events to my_story")
    story_handle = return_tuple[1]
    story_handle.log_event("py_event")
    story_handle.log_event("py_event.2")
    story_handle.log_event("py_event.3")
    story_handle.log_event("py_event.4")

# Release the story
return_code = client.ReleaseStory("py_chronicle", "my_story")
print("\nclient.ReleaseStory() returned:", return_code)

# Disconnect the client
return_code = client.Disconnect()
print("\nclient.Disconnect() returned:", return_code)

Installation and Setup:

  1. Build and install ChronoLog, ensuring py_chronolog_client is compiled and available in your library directory.
  2. Update environment variables:
    • Add the library path to LD_LIBRARY_PATH:
      export LD_LIBRARY_PATH=/path/to/chronolog/lib:$LD_LIBRARY_PATH
    • Add the library path to PYTHONPATH:
      export PYTHONPATH=/path/to/chronolog/lib:$PYTHONPATH
  3. Create a symbolic link for the Python client:
    ln -s /path/to/chronolog/lib/py_chronolog_client.[python-version-linux-version].so /path/to/chronolog/lib/py_chronolog_client.so

The Python Client enables seamless interaction with ChronoLog, making it highly adaptable for various scenarios such as event logging, data analysis, and workflow integration.


Each client offers unique capabilities tailored to different needs, from direct API access to interactive and automated operations. Choose the client that best suits your workflow, and refer to the provided examples and scripts to get started effectively.