Operations 17 min read

How Sampler Turns Shell Commands into Real‑Time Visual Metrics

Sampler is a lightweight tool that lets you execute shell commands, visualize their output, and set up alerts—all via a simple YAML configuration, making it ideal for on‑the‑fly monitoring of databases, message queues, deployments, and remote servers.

Efficient Ops
Efficient Ops
Efficient Ops
How Sampler Turns Shell Commands into Real‑Time Visual Metrics

Sampler is a tool for executing shell commands, visualizing their output, and triggering alerts, configured through a simple YAML file.

Why you need it?

You can sample any running process directly from the terminal—watch database changes, monitor in‑flight MQ messages, trigger deployment scripts and receive notifications upon completion.

If you can obtain a metric with a shell command, Sampler can immediately visualize it.

Installation

macOS

<code>brew cask install sampler</code>

or

<code>sudo curl -Lo /usr/local/bin/sampler https://github.com/sqshq/sampler/releases/download/v1.0.3/sampler-1.0.3-darwin-amd64
sudo chmod +x /usr/local/bin/sampler</code>

Linux

<code>sudo wget https://github.com/sqshq/sampler/releases/download/v1.0.3/sampler-1.0.3-linux-amd64 -O /usr/local/bin/sampler
sudo chmod +x /usr/local/bin/sampler</code>
Note: Install the libasound2-dev system library for sound alerts (e.g., apt install libasound2-dev ).

Windows (experimental)

Recommended to run in an advanced console emulator such as Cmder.

Download .exe

Usage

Specify a shell command; Sampler runs it at the defined rate and visualizes the output. Typical workflow: Define shell commands in a YAML config file. Run sampler -c config.yml . Adjust component size and position in the UI.

Existing monitoring solutions

Sampler is not a replacement for full‑blown monitoring systems; it is a quick‑setup developer tool.

If setting up Grafana + Prometheus feels excessive, Sampler can work without a server, database, or deployment—just provide shell commands.

Do I need to install it on every server?

No. You can run Sampler locally and still collect telemetry from multiple remote machines via SSH in the init command.

Components

Below are example configurations for each component type (macOS‑compatible scripts).

Runchart

<code>runcharts:
  - title: Search engine response time
    rate-ms: 500
    scale: 2
    legend:
      enabled: true
      details: false
    items:
      - label: GOOGLE
        sample: curl -o /dev/null -s -w '%{time_total}' https://www.google.com
        color: 178
      - label: YAHOO
        sample: curl -o /dev/null -s -w '%{time_total}' https://search.yahoo.com
      - label: BING
        sample: curl -o /dev/null -s -w '%{time_total}' https://www.bing.com</code>

Sparkline

<code>sparklines:
  - title: CPU usage
    rate-ms: 200
    scale: 0
    sample: ps -A -o %cpu | awk '{s+=$1} END {print s}'
  - title: Free memory pages
    rate-ms: 200
    scale: 0
    sample: memory_pressure | grep 'Pages free' | awk '{print $3}'</code>

Barchart

<code>barcharts:
  - title: Local network activity
    rate-ms: 500
    scale: 0
    items:
      - label: UDP bytes in
        sample: nettop -J bytes_in -l 1 -m udp | awk '{sum += $4} END {print sum}'
      - label: UDP bytes out
        sample: nettop -J bytes_out -l 1 -m udp | awk '{sum += $4} END {print sum}'
      - label: TCP bytes in
        sample: nettop -J bytes_in -l 1 -m tcp | awk '{sum += $4} END {print sum}'
      - label: TCP bytes out
        sample: nettop -J bytes_out -l 1 -m tcp | awk '{sum += $4} END {print sum}'</code>

Gauge

<code>gauges:
  - title: Minute progress
    rate-ms: 500
    scale: 2
    percent-only: false
    color: 178
    cur:
      sample: date +%S
    max:
      sample: echo 60
    min:
      sample: echo 0
  - title: Year progress
    cur:
      sample: date +%j
    max:
      sample: echo 365
    min:
      sample: echo 0</code>

Textbox

<code>textboxes:
  - title: Local weather
    rate-ms: 10000
    sample: curl wttr.in?0ATQF
    border: false
    color: 178
  - title: Docker containers stats
    rate-ms: 500
    sample: docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.PIDs}}"</code>

Asciibox

<code>asciiboxes:
  - title: UTC time
    rate-ms: 500
    font: 3d
    border: false
    color: 43
    sample: env TZ=UTC date +%r</code>

Extra Features

Triggers

Triggers can execute conditional actions such as visual or sound alerts, or arbitrary shell commands.

<code>gauges:
  - title: MINUTE PROGRESS
    position: [[0, 18], [80, 0]]
    cur:
      sample: date +%S
    max:
      sample: echo 60
    min:
      sample: echo 0
    triggers:
      - title: CLOCK BELL EVERY MINUTE
        condition: '[ $label == "cur" ] && [ $cur -eq 0 ] && echo 1 || echo 0'
        actions:
          terminal-bell: true
          sound: true
          visual: false
          script: say -v samantha `date +%I:%M%p`</code>

Example: alert when search‑engine latency exceeds a threshold.

<code>runcharts:
  - title: SEARCH ENGINE RESPONSE TIME (sec)
    rate-ms: 200
    items:
      - label: GOOGLE
        sample: curl -o /dev/null -s -w '%{time_total}' https://www.google.com
      - label: YAHOO
        sample: curl -o /dev/null -s -w '%{time_total}' https://search.yahoo.com
    triggers:
      - title: Latency threshold exceeded
        condition: echo "$prev < 0.3 && $cur > 0.3" | bc -l
        actions:
          terminal-bell: true
          sound: true
          visual: true
          script: 'say alert: ${label} latency exceeded ${cur} second'</code>

Interactive Shell Support

Besides

sample

, you can define

init

(run once before sampling) and

transform

(post‑process sample output) commands.

Basic mode

<code>textboxes:
  - title: MongoDB polling
    rate-ms: 500
    init: mongo --quiet --host=localhost test
    sample: Date.now();
    transform: echo result = $sample</code>

PTY mode

Use pseudo‑terminal mode when the interactive shell’s stdin is not a TTY.

<code>textboxes:
  - title: Neo4j polling
    pty: true
    init: cypher-shell -u neo4j -p pwd --format plain
    sample: RETURN rand();
    transform: echo "$sample" | tail -n 1
  - title: Top on a remote server
    pty: true
    init: ssh -i ~/user.pem [email protected]
    sample: top</code>

Multi‑step init

<code>textboxes:
  - title: Java application uptime
    multistep-init:
      - java -jar jmxterm-1.0.0-uber.jar
      - open host:port
      - bean java.lang:type=Runtime
    sample: get Uptime</code>

Variables

Extract repeated patterns into a

variables

section or pass them via

-v/--variable

. System environment variables are also accessible.

<code>variables:
  mongoconnection: mongo --quiet --host=localhost test
barcharts:
  - title: MongoDB documents by status
    items:
      - label: IN_PROGRESS
        init: $mongoconnection
        sample: db.getCollection('events').find({status:'IN_PROGRESS'}).count()
      - label: SUCCESS
        init: $mongoconnection
        sample: db.getCollection('events').find({status:'SUCCESS'}).count()
      - label: FAIL
        init: $mongoconnection
        sample: db.getCollection('events').find({status:'FAIL'}).count()</code>

Color Themes

<code>theme: light
sparklines:
  - title: CPU usage
    sample: ps -A -o %cpu | awk '{s+=$1} END {print s}'</code>

Real‑World Scenarios

Databases

Use interactive

init

scripts to establish a single connection and reuse it for sampling.

MySQL

<code># prerequisite: installed mysql shell
variables:
  mysql_connection: mysql -u root -s --database mysql --skip-column-names
sparklines:
  - title: MySQL (random number example)
    pty: true
    init: $mysql_connection
    sample: select rand();</code>

PostgreSQL

<code># prerequisite: installed psql shell
variables:
  PGPASSWORD: pwd
  postgres_connection: psql -h localhost -U postgres --no-align --tuples-only
sparklines:
  - title: PostgreSQL (random number example)
    init: $postgres_connection
    sample: select random();</code>

MongoDB

<code># prerequisite: installed mongo shell
variables:
  mongo_connection: mongo --quiet --host=localhost test
sparklines:
  - title: MongoDB (random number example)
    init: $mongo_connection
    sample: Math.random();</code>

Neo4j

<code># prerequisite: installed cypher shell
variables:
  neo4j_connection: cypher-shell -u neo4j -p pwd --format plain
sparklines:
  - title: Neo4j (random number example)
    pty: true
    init: $neo4j_connection
    sample: RETURN rand();
    transform: echo "$sample" | tail -n 1</code>

Kafka

<code>variables:
  kafka_connection: $KAFKA_HOME/bin/kafka-consumer-groups --bootstrap-server localhost:9092
runcharts:
  - title: Kafka lag per consumer group
    rate-ms: 5000
    scale: 0
    items:
      - label: A->B
        sample: $kafka_connection --group group_a --describe | awk 'NR>1 {sum += $5} END {print sum}'
      - label: B->C
        sample: $kafka_connection --group group_b --describe | awk 'NR>1 {sum += $5} END {print sum}'
      - label: C->D
        sample: $kafka_connection --group group_c --describe | awk 'NR>1 {sum += $5} END {print sum}'</code>

Docker

<code>textboxes:
  - title: Docker containers stats
    sample: docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDs}}"</code>

SSH

<code>variables:
  sshconnection: ssh -i ~/my-key-pair.pem [email protected]
textboxes:
  - title: SSH
    pty: true
    init: $sshconnection
    sample: top</code>

JMX

<code># prerequisite: download jmxterm jar
textboxes:
  - title: Java application uptime
    multistep-init:
      - java -jar jmxterm-1.0.0-uber.jar
      - open host:port
      - bean java.lang:type=Runtime
    sample: get Uptime
    transform: echo $sample | tr -dc '0-9' | awk '{printf "%.1f min", $1/1000/60}'</code>

*Source: GitHub, compiled by FB editor secist. Please credit FreeBuf.COM when reproducing.

monitoringDevOpsMetricssamplershellvisualization
Efficient Ops
Written by

Efficient Ops

This public account is maintained by Xiaotianguo and friends, regularly publishing widely-read original technical articles. We focus on operations transformation and accompany you throughout your operations career, growing together happily.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.