A lightweight **command-line client for Apache Pulsar** written in Go. It supports producing, reading, and consuming messages from Pulsar topics — using structured logging via **logrus** and flexible command-line flags powered by **cobra**.
| .gitignore | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| Makefile | ||
| README.md | ||
Pulsar CLI
A lightweight command-line client for Apache Pulsar written in Go.
It supports producing, reading, and consuming messages from Pulsar topics — with colored logs on stderr and message payloads on stdout for easy piping.
✨ Features
- Reader — read messages from a topic (no subscription)
- Consumer — consume messages with a subscription
- Regex topic patterns (
--regex) to match multiple topics - Producer — publish messages from
stdinor a file - Custom delimiters for
stdinmode (e.g.--delimiter="\n\n") - Message properties via
--property key=value - Chunking (
--enable-chunking) for large payloads - Batching (
--enable-batching) for throughput - Colored logs with
logrusonstderr - Payloads printed to
stdoutfor UNIX-style piping (jq,grep, etc.) - Environment-based configuration (
PULSAR_URL,PULSAR_JWT) - Static, portable builds (no dependencies)
📦 Installation
🧰 Build from Source
Clone and build:
git clone https://forge.ext.d2ux.net/Atlas/pulsar-cli
cd pulsar-cli
go mod tidy
make build
Binary will be at ./pulsar-cli.
For static builds:
make build-linux
make build-macos
make build-windows
⚙️ Environment Variables
| Variable | Description | Example |
|---|---|---|
PULSAR_URL |
Pulsar broker URL | pulsar://localhost:6650 |
PULSAR_JWT |
(Optional) JWT token for authentication | eyJhbGciOiJIUzI1NiIsInR5cCI6... |
🧠 Usage
Reader
Read messages from a topic without subscription:
pulsar-cli reader -t "my-topic"
Consumer
Consume messages with a subscription:
pulsar-cli consumer -t "my-topic" -s "my-subscription"
Consume using a Regex pattern
You can subscribe to multiple matching topics using a regex pattern with --regex:
pulsar-cli consumer -t "persistent://public/default/my-topic-.*" -s "multi-sub" --regex
This will automatically receive messages from all topics matching the pattern, such as:
persistent://public/default/my-topic-1persistent://public/default/my-topic-foopersistent://public/default/my-topic-bar
Producer
Publish messages (from stdin or a file) to a topic.
From stdin
echo "Hello, Pulsar!" | pulsar-cli producer -t "my-topic"
With custom delimiter
pulsar-cli producer -t "my-topic" -d "\n\n"
From a file
pulsar-cli producer -t "my-topic" -f ./data.json
With message properties
echo "hi" | pulsar-cli producer -t "my-topic" -p app=demo -p env=dev
Enable chunking
cat large.json | pulsar-cli producer -t "my-topic" --enable-chunking
Enable batching
seq 1 10000 | pulsar-cli producer -t "my-topic" --enable-batching
🧾 Command Reference
Reader
| Flag | Description |
|---|---|
-t, --topic |
Topic to read from |
Consumer
| Flag | Description |
|---|---|
-t, --topic |
Topic to consume from (or regex pattern if --regex is used) |
-s, --subscription |
Subscription name |
--regex |
Treat the topic as a regex pattern to match multiple topics |
Producer
| Flag | Description |
|---|---|
-t, --topic |
Topic to produce to |
-p, --property key=value |
Message property (repeatable) |
-f, --file |
Read payload from file (sends once per file) |
-d, --delimiter |
Custom message delimiter for stdin mode (default: newline) |
-c, --enable-chunking |
Enable Pulsar message chunking for large payloads |
-b, --enable-batching |
Enable Pulsar message batching |
🪶 Example Session
export PULSAR_URL="pulsar://localhost:6650"
export PULSAR_JWT="your-jwt-token"
# Start consumer for a single topic
pulsar-cli consumer -t "demo-topic" -s "demo-sub"
# Start consumer for all topics matching demo-*
pulsar-cli consumer -t "persistent://public/default/demo-.*" -s "demo-sub" --regex
# Produce messages from stdin
echo '{"msg":"hi"}' | pulsar-cli producer -t "demo-topic"
# Produce from file with properties
pulsar-cli producer -t "demo-topic" -f ./payload.json -p app=cli -p format=json
🧾 Logging & Streams
Separation of streams
stdout→ message payloads (clean, newline-terminated)stderr→ logs (colored, human-readable)
Piping examples
Ignore logs:
pulsar-cli reader -t "demo-topic" 2>/dev/null | jq .
Split logs and payloads:
pulsar-cli consumer -t "demo-topic" -s "demo-sub" 1>payloads.log 2>operator.log
Inspect logs only:
pulsar-cli consumer -t "demo-topic" -s "demo-sub" >/dev/null
Sample output
stderr (logs):
INFO[0000] Consuming from topic pattern persistent://public/default/demo-.* with subscription demo-sub
INFO[0002] received message topic=persistent://public/default/demo-foo msgID=0001 publishAt=2025-11-11T10:00:00Z
stdout (payloads):
{"msg":"hi"}
🧩 Tech Stack
🚀 Future Work
- Add schema decoding (JSON/Avro)
- Add topic metadata inspection command
- Add message replay support
- Add version info (build time, commit, tag)
- Add multi-topic reader (simulate regex in reader mode)
📄 License
MIT License © 2025 Matthias Petermann