ebarti / dd-assignment

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Built Late 2021

Datadog Take Home Exercise

By Eloi Barti


Running the exercise

There are two options to run the exercise:

  1. Build from source
  2. Use one of the pre-built binaries

Build from source

  1. Install Go 1.17+
  2. Clone the repository to $GOPATH/src/github.com/ebarti/dd-assignment
  3. Run go build .
  4. Binary is built as dd-assignment

Using one of the pre-built binaries

Check the /bin directory for the binaries.

Getting Started

Run ./dd-assignment --help to see the available options.

About my solution

I chose Go for my implementation as the language features a set of concurrency primitives that are very useful for this exercise. I used cobra to handle some CLI basics like flags, help menus, etc.

Here is the architecture of the solution:

 SERVICE
┌───────────────────────────────────────────────┐
│  ┌─────────────────┐                          │
│  │  FILE READER    │                          │
│  └───────┬─────────┘                          │
│          │Message           ┌───────────────┐ │
│          │              ┌───► LOG MONITOR   │ │
│  ┌───────▼────────┐     │   │               │ │
│  │                ├─────┘   └───────────────┘ │
│  │  LOG PIPELINE  │ProcessedLog               │
│  │                ├─────┐   ┌───────────────┐ │
│  └───────┬────────┘     │   │               │ │
│          │              └───► LOG MONITOR   │ │
│          │ ProcessedLog     └───────────────┘ │
│  ┌───────▼────────┐               .....       │
│  │METRICS PIPELINE│                           │
│  └───────┬────────┘                           │
│          │ []MetricSample                     │
│  ┌───────▼────────┐                           │
│  │    METRICS     │                           │
│  │   AGGREGATOR   │                           │
│  └────────────────┘                           │
└───────────────────────────────────────────────┘

File Reader

  • Reads line by line from the input file
  • Creates a Message for each line
  • Feeds the message to its output channel

Log Pipeline

  • Reads the Message from its input channel
  • Processes the message according to its LogProcessorFunc
  • Asynchronously feeds the processed message to its output channel and all observing LogMonitors

Log Monitor

  • Reads the processedLog from its input channel
  • Generates a metric sample for each processed log
  • Aggregates the metric according to the monitor's configuration
  • Monitors the value of the metric and, if the value is above the threshold, prints an alert to the console

Metrics Pipeline

  • Reads the processedLog from its input channel
  • Generates a (set of) metric sample(s) for each processed log LogFilter and a LogMeasure. Tags the metrics according to its groupBy configuration
  • Sends the samples to its output channel

Metrics Aggregator

  • Reads the metric samples from its input channel
  • Aggregates metrics by interval
  • When an interval is complete, it flushes the metrics and renders them to the console

Notes

  • As the log monitor and the metrics aggregator run on different goroutines, the order of the console output is not guaranteed.

  • As I think it is good practice (and it is so simple to do in Go), I have vendored all the project dependencies via go mod vendor and are under the vendor directory.

Future improvements

Order of output

If the output needs to be ordered, a custom logger could be implemented. This logger would be fed logs and timestamps, and would keep a cache of some logs to be printed. Multiple conditions could be implemented on how the cache is flushed, like:

  • If the cache is full (basic)
  • If the last M logs received are all of increasing timestamp The flushing would obviously flush the cache in increasing order of timestamp.

Reader becomes a fully fledged agent

My initial implementation of the solution included a simple "datadog-like" agent. However, due to the added complexity and the little value it added to my solution, I decided to scrap it. A future improvement would be to create a fully fledged agent, able to tail log files in real-time, handle log file rotations, etc.

Backend exposes an API

Right now the file-reader (the closest to a datadog-agent in this solution) is using a channel to send the messages it reads. A future improvement would be to decouple it from the backend by exposing an API for the agent to send the messages.

Decoupling

There is a bit of coupling between the different components of the solution. Although some of my components do actually already implement interfaces like Restartable, it would be a good idea to clean up the code so that the components are referenced by their interface rather than a pointer.

Types of Metrics

Right now only count based metrics are supported. Some other metrics could be added, like:

  • Rates
  • Gauges
  • Histograms
  • etc.

Service metrics

Right now there are no metrics on the actual backend. It would be nice to know things like ingestion latency, how many resources the backend is using, etc.

About


Languages

Language:Go 100.0%