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.
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
variablessection 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
initscripts 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.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.