Skip to content

A C++, header only library for DataDog communication on Windows, Mac, and Linux

License

Notifications You must be signed in to change notification settings

garrettsickles/DogFood

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

62 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DogFood

(See us on DataDog's developer site)

Build Status Build status

A C++ API for reporting DataDog metrics

  • Header Only
  • Stateless
  • Cross Platform
  • UDP and UDS (linux only) communication with DogStatsD agent

Simple Example

Running the barebones example program in example/simple_example.cpp produces the following:

DataDog Capture

Before You Start

This project is used for communicating with a DataDog Agent

If you do not have a DataDog Agent installed, please install it and connect it to your account!

Configuration

UDP - User Datagram Protocol (Custom)

Configure DogFood to send metrics to a custom host and port over UDP

Here is an example in example/simple_example_udp.cpp

DogFood::Send(DogFood::Metric(
    "DogFood.MetricTest",
    49.5555,
    DogFood::Counter,
    0.75,
    DogFood::Tags({ { "f", "9" }, { "g", "8" } })
), DogFood::UDP("127.0.0.1", 8125));

UDS - Unix Domain Sockets (Custom)

Configure DogFood to send metrics to a custom host and port over UDP

Here is an example in example/simple_example_linux_uds.cpp

DogFood::Send(DogFood::Metric(
    "DogFood.MetricTest",
    49.5555,
    DogFood::Counter,
    0.75,
    DogFood::Tags({ { "f", "9" }, { "g", "8" } })
), DogFood::UDS("/var/run/datadog/dsd.socket"));

Note:

  1. Set datadog agent to use UDS
    • In /etc/datadog-agent/datadog.yaml, set dogstatsd_socket to /var/run/datadog/dsd.socket
      • e.g. - dogstatsd_socket: /var/run/datadog/dsd.socket
  2. Add permissions for dd-agent
    • $ mkdir /var/run/datadog/
    • $ sudo chown dd-agent:dd-agent -R /var/run/datadog/

UDP - User Datagram Protocol (At build time)

Configure DogFood to send metrics to a custom host and port over UDP

Here is an example in example/simple_example.cpp

// At compile time override the default host & default port
//   (Please do not compile with 255.255.255.255)
g++ (...) -DDOGSTATSD_HOST="255.255.255.255" -DDOGSTATSD_PORT=12345

// At compile time in the source
#define DOGSTATSD_HOST "127.0.0.1"
#define DOGSTATSD_PORT 8125


// By default will send over UDP to DOGSTATSD_HOST:DOGSTATSD_PORT
DogFood::Send(DogFood::Metric(
    "DogFood.MetricTest",
    49.5555,
    DogFood::Counter,
    0.75,
    DogFood::Tags({ { "f", "9" }, { "g", "8" } })
));

Example

// Only need to include this file
// No linkage needed
#include <DogFood/DogFood.h>

// ...std::this_thread::sleep_for
#include <thread>

int main()
{
    // Metrics Forever
    while (true) {
        // Report a 'metric'
        //    - Named "DogFood.MetricTest"
        //    - Value of 49.5555
        //    - Type of Counter
        //    - Sampled rate of 75%
        //    - Tags of f="9" and g="8"
        DogFood::Send(DogFood::Metric(
            "DogFood.MetricTest",
            49.5555,
            DogFood::Counter,
            0.75,
            DogFood::Tags({ { "f", "9" }, { "g", "8" } })
        ));
        
        // Report an 'event'
        //    - Named "DogFood Event"
        //    - Message of "The event was invoked"
        //    - At a the current time
        DogFood::Send(DogFood::Event(
            "DogFood Event",
            "The event was invoked",
            time(NULL)
        ));
        
        // Report a 'service_check'
        //    - Named "DogFood Service Check"
        //    - Level of Warning
        //    - At a the current time
        DogFood::Send(DogFood::ServiceCheck(
            "DogFood Service Check",
            DogFood::Status::Warning,
            time(NULL)
        ));
        
        // Sleep for 30 seconds
        std::this_thread::sleep_for(std::chrono::seconds(30));
    }
}

Metric

////////////////////////////////////////////////////////////////
//                                                            //
//     888b     d888          888            d8b              //
//     8888b   d8888          888            Y8P              //
//     88888b.d88888          888                             //
//     888Y88888P888  .d88b.  888888 888d888 888  .d8888b     //
//     888 Y888P 888 d8P  Y8b 888    888P"   888 d88P"        //
//     888  Y8P  888 88888888 888    888     888 888          //
//     888   "   888 Y8b.     Y88b.  888     888 Y88b.        //
//     888       888  "Y8888   "Y888 888     888  "Y8888P     //
//                                                            //
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Format
//
//     'metric.name:value|type|@sample_rate|#tag1:value,tag2'
//
//     - metric.name
//         A string with no colons, bars, or @ characters.
//         See the metric naming policy.
//
//     - value
//         An integer or float.
//
//     - type
//         'c' for counter, 'g' for gauge, 'ms' for timer,
//         'h' for histogram, 's' for set.
//
//     - @sample_rate
//         (Optional)
//             A float between 0 and 1, inclusive.
//             Only works with counter, histogram,
//             and timer metrics. Default is 1
//             (i.e. sample 100% of the time).
//
//     - tags
//         (Optional)
//             A comma separated list of tags.
//             Use colons for key/value tags, i.e. env:prod.
//             The key device is reserved; Datadog drops a
//             user-added tag like device:foobar.
//

////////////////////////////////////////////////////////////////
// Samples
//
//     # Increment the page.views counter
//     'page.views:1|c'
//
//     # Record the fuel tank is half-empty
//     'fuel.level:0.5|g'
//
//     # Sample the song length histogram half of the time
//     'song.length:240|h|@0.5'
//
//     # Track a unique visitor to the site
//     'users.uniques:1234|s'
//
//     # Increment the active users counter, tag by country
//     'users.online:1|c|#country:china'
//
//     # Track active China users and use a sample rate
//     'users.online:1|c|@0.5|#country:china'
//

////////////////////////////////////////////////////////////////
// Type
//
//     The 'Type' of a DataDog 'Metric'
//
enum Type {
    Counter,
    Gauge,
    Timer,
    Histogram,
    Set
};

std::string Metric(
    const std::string _name,
    const ValueType   _value,
    const Type        _type,
    const double      _rate = 1.0,
    const Tags&       _tags = Tags()
);

Event

////////////////////////////////////////////////////////////////
//                                                            //
//        8888888888                            888           //
//        888                                   888           //
//        888                                   888           //
//        8888888    888  888  .d88b.  88888b.  888888        //
//        888        888  888 d8P  Y8b 888 "88b 888           //
//        888        Y88  88P 88888888 888  888 888           //
//        888         Y8bd8P  Y8b.     888  888 Y88b.         //
//        8888888888   Y88P    "Y8888  888  888  "Y888        //
//                                                            //
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Format
//
//     '_e{title.length,text.length}:title|text|d:timestamp|
//      h:hostname|p:priority|t:alert_type|#tag1,tag2'
//
//     - _e
//         The datagram must begin with _e
//
//     - title
//         Event title.
//
//     - text
//         Event text.
//         Insert line breaks with an escaped slash (\\n)
//
//     - d:timestamp
//         (Optional)
//             Add a timestamp to the event.
//             Default is the current Unix epoch timestamp.
//
//     - h:hostname
//         (Optional)
//             Add a hostname to the event. No default.
//
//     - k:aggregation_key
//         (Optional)
//             Add an aggregation key to group the event with
//             others that have the same key. No default.
//
//     - p:priority
//         (Optional)
//             Set to ‘normal’ or ‘low’. Default ‘normal’.
//
//     - s:source_type_name
//         (Optional)
//             Add a source type to the event. No default.
//
//     - t:alert_type
//         (Optional)
//             Set to ‘error’, ‘warning’, ‘info’ or ‘success’.
//             Default ‘info’.
//
//     - #tag1:value1,tag2,tag3:value3...
//         (Optional)
//             The colon in tags is part of the tag list string
//             and has no parsing purpose like for the other
//             parameters. No default.
//

////////////////////////////////////////////////////////////////
// Samples
//
//     # Send an exception
//     '_e{21,36}:An exception occurred|Cannot parse CSV file
//      from 10.0.0.17|t:warning|#err_type:bad_file'
//
//     # Send an event with a newline in the text
//     '_e{21,42}:An exception occurred|Cannot parse JSON
//      request:\\n{"foo: "bar"}|p:low|#err_type:bad_request'
//

////////////////////////////////////////////////////////////////
// Priority
//
//     The 'Priority' of a DataDog 'Event'
//
enum class Priority {
    Low,
    Normal
};

////////////////////////////////////////////////////////////////
// Alert
//
//     The 'Alert' type of a DataDog 'Event'
//
enum class Alert {
    Info,
    Success,
    Warning,
    Error
};

std::string Event(
    const std::string _title,
    const std::string _text,
    const Numeric     _timestamp         = 0,
    const std::string _hostname          = "",
    const std::string _aggregation_key   = "",
    const Priority    _priority          = Priority::Normal,
    const std::string _source_type_name  = "",
    const Alert       _alert_type        = Alert::Info,
    const Tags&       _tags              = Tags()
);

Service Check

////////////////////////////////////////////////////////////////
//                                                            //
//   .d8888b.                            d8b                  //
//  d88P  Y88b                           Y8P                  //
//  Y88b.                                                     //
//   "Y888b.    .d88b.  888d888 888  888 888  .d8888b .d88b.  //
//      "Y88b. d8P  Y8b 888P"   888  888 888 d88P"   d8P  Y8b //
//        "888 88888888 888     Y88  88P 888 888     88888888 //
//  Y88b  d88P Y8b.     888      Y8bd8P  888 Y88b.   Y8b.     //
//   "Y8888P"   "Y8888  888       Y88P   888  "Y8888P "Y8888  //
//                                                            //
//                                                            //
//                                                            //
//         .d8888b.  888                        888           //
//        d88P  Y88b 888                        888           //
//        888    888 888                        888           //
//        888        88888b.   .d88b.   .d8888b 888  888      //
//        888        888 "88b d8P  Y8b d88P"    888 .88P      //
//        888    888 888  888 88888888 888      888888K       //
//        Y88b  d88P 888  888 Y8b.     Y88b.    888 "88b      //
//         "Y8888P"  888  888  "Y8888   "Y8888P 888  888      //
//                                                            //
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// Format
//     '_sc|name|status|d:timestamp|h:hostname|#tag1:value1,
//      tag2,tag3:value3,...|m:service_check_message'
//
//     - _sc
//         The datagram must begin with _sc.
//     - name
//         Service check name.
//     - status
//         Integer corresponding to the check status.
//         (OK = 0, WARNING = 1, CRITICAL = 2, UNKNOWN = 3).
//     - d:timestamp
//         (Optional)
//             Add a timestamp to the event.
//             Default is the current Unix epoch timestamp.
//     - h:hostname
//         (Optional)
//             Add a hostname to the event. No default.
//     - #tag1:value1,tag2,tag3:value3...
//         (Optional)
//             The colon in tags is part of the tag list string
//             and has no parsing purpose like for the other
//             parameters. No default.
//     - m:service_check_message
//         (Optional)
//             Add a message describing the current state of
//             the service check. This field MUST be positioned
//             last among the metadata fields. No default.

////////////////////////////////////////////////////////////////
// Samples
//
//     # Send a CRITICAL status for a remote connection
//     '_sc|Redis connection|2|#redis_instance:10.0.0.16:6379|
//      m:Redis connection timed out after 10s'

////////////////////////////////////////////////////////////////
// Status
//
//     The 'Status' of a DataDog 'Service Check'
//
enum class Status {
    Ok,
    Warning,
    Critical,
    Unknown
};

////////////////////////////////////////////////////////////////
// Template
//
//     Numeric should be an integral or floating-point type
//
std::string ServiceCheck(
    const std::string _name,
    const Status      _status,
    const Numeric     _timestamp = 0,
    const std::string _hostname  = "",
    const std::string _message   = "",
    const Tags&       _tags      = Tags()
);