Awesome Go

rabtap

CategoryMessaging
SubcategoryMessaging
Stars290

RabbitMQ swiss army knife cli app

About rabtap

This large README is shown as a plain-text preview. Read the full README at the source

# rabtap - RabbitMQ wire tap

![Build Status](https://github.com/jandelgado/rabtap/workflows/run%20tests/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/jandelgado/rabtap/badge.svg?branch=master)](https://coveralls.io/github/jandelgado/rabtap?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/jandelgado/rabtap)](https://goreportcard.com/report/github.com/jandelgado/rabtap)

Swiss army knife for RabbitMQ. Tap/Pub/Sub messages, create/delete/bind queues
and exchanges, inspect broker.

## Contents

<!-- vim-markdown-toc GFM -->

- [Features](#features)
- [Screenshots](#screenshots)
  - [Show broker topology](#show-broker-topology)
  - [Visualize broker topology with graphviz](#visualize-broker-topology-with-graphviz)
  - [Tap messages](#tap-messages)
- [Installation](#installation)
  - [Docker image](#docker-image)
  - [Pre-compiled binaries](#pre-compiled-binaries)
  - [Arch Linux](#arch-linux)
  - [Installation from source](#installation-from-source)
- [Usage](#usage)
  - [Command overview](#command-overview)
  - [Broker URI specification](#broker-uri-specification)
    - [Authentication](#authentication)
  - [Environment variables](#environment-variables)
    - [Default RabbitMQ broker](#default-rabbitmq-broker)
    - [Default RabbitMQ management API endpoint](#default-rabbitmq-management-api-endpoint)
    - [Default RabbitMQ TLS config](#default-rabbitmq-tls-config)
    - [Colored output](#colored-output)
  - [Command reference and examples](#command-reference-and-examples)
    - [Broker info](#broker-info)
    - [Wire-tapping messages](#wire-tapping-messages)
      - [Tap all messages published or delivered (RabbitMQ FireHose)](#tap-all-messages-published-or-delivered-rabbitmq-firehose)
        - [Replaying messages from the FireHose exchange](#replaying-messages-from-the-firehose-exchange)
      - [Connect to multiple brokers](#connect-to-multiple-brokers)
      - [Message recorder](#message-recorder)
    - [Subscribe messages](#subscribe-messages)
    - [Publish messages](#publish-messages)
    - [Poor mans shovel](#poor-mans-shovel)
    - [Close connection](#close-connection)
    - [Exchange commands](#exchange-commands)
    - [Queue commands](#queue-commands)
  - [Format specification for tap and sub command](#format-specification-for-tap-and-sub-command)
  - [JSON message format](#json-message-format)
  - [Filtering output](#filtering-output)
    - [Filtering expressions](#filtering-expressions)
      - [Evaluation context](#evaluation-context)
      - [Examples](#examples)
    - [Type reference](#type-reference)
      - [Exchange type](#exchange-type)
      - [Queue type](#queue-type)
      - [Binding type](#binding-type)
      - [Connection type](#connection-type)
      - [Channel type](#channel-type)
      - [Message type](#message-type)
- [Build from source](#build-from-source)
  - [Download and build using go install](#download-and-build-using-go-install)
  - [Build using Makefile and tests](#build-using-makefile-and-tests)
  - [Experimental WASM/wasip1 port](#experimental-wasmwasip1-port)
- [Test data generator](#test-data-generator)
- [Contributing](#contributing)
- [Author](#author)
- [Copyright and license](#copyright-and-license)

<!-- vim-markdown-toc -->

## Features

- tap to messages being sent to exchanges using RabbitMQ
  exchange-to-exchange bindings without affecting actual message delivery (aka _tapping_)
- display broker related information using the
  [RabbitMQ REST management API](https://rawcdn.githack.com/rabbitmq/rabbitmq-management/rabbitmq_v3_6_14/priv/www/api/index.html)
- save messages and meta data for later analysis and replay
- publish messages to exchanges
- consume messages from queues and streams (subscribe)
- filter output using flexible expressions
- supports TLS
- no runtime dependencies (statically linked golang single file binary)
- simple to use command line tool
- runs on Linux, Windows, Mac and wherever you can compile go

## Screenshots

### Show broker topology

Output of `rabtap info` command:

![info mode](doc/images/info.png)

Output of `rabtap info --stats` command, showing additional statistics:

![info mode](doc/images/info-stats.png)

### Visualize broker topology with graphviz

Using the `--format=dot` option, the `info` command can generate output in the
[dot format](https://graphviz.org/doc/info/lang.html), which can be visualized
using graphviz, e.g. `rabtap info --show-default --format dot | dot -T svg >
mybroker.svg`. The resulting SVG file can be visualized with a web browser.

![info mode](doc/images/info-dot.png)

### Tap messages

Output of rabtap in `tap` mode, showing message meta data and the message body:

![info mode](doc/images/tap.png)

## Installation

### Docker image

A docker image is provided so rabtap can be used as a docker container, e.g.

```console
$ docker run --rm -ti ghcr.io/jandelgado/rabtap:latest
```

### Pre-compiled binaries

Pre-compiled binaries can be downloaded for multiple platforms from the
[releases page](https://github.com/jandelgado/rabtap/releases).

### Arch Linux

Rabtap can be installed from the Arch Linux User Repository (AUR):

```console
$ yay -S rabtap
```

### Installation from source

See the [build from source section](#build-from-source) if you prefer to
compile from source.

## Usage

```text

rabtap - RabbitMQ wire tap.                    github.com/jandelgado/rabtap

Usage:
  rabtap info [--api=APIURI] [--consumers] [--stats] [--filter=EXPR] [--omit-empty]
              [--show-default] [--mode=MODE] [--format=FORMAT] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap tap EXCHANGES [--uri=URI] [--saveto=DIR] [--format=FORMAT|--json]  [--limit=NUM]
              [--idle-timeout=DURATION] [--filter=EXPR] [--silent] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap (tap --uri=URI EXCHANGES)... [--saveto=DIR] [--format=FORMAT|--json]  [--limit=NUM]
              [--idle-timeout=DURATION] [--filter=EXPR] [--silent] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap sub QUEUE [--uri URI] [--saveto=DIR] [--format=FORMAT|--json] [--limit=NUM]
              [--offset=OFFSET] [--args=KV]... [(--reject [--requeue])] [--silent]
              [--filter=EXPR] [--idle-timeout=DURATION] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap pub  [--uri=URI] [SOURCE] [--exchange=EXCHANGE] [--format=FORMAT|--json]
              [--routingkey=KEY | (--header=KV)...] [ (--property=KV)... ] [--confirms]
              [--mandatory] [--delay=DURATION | --speed=FACTOR] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap exchange create EXCHANGE [--uri=URI] [--type=TYPE] [--args=KV]...
              [--autodelete] [--transient] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap exchange bind EXCHANGE to DESTEXCHANGE [--uri=URI]
              (--bindingkey=KEY | (--header=KV)... (--all|--any)) [TLSOPTIONS] [COMMON OPTIONS]
  rabtap exchange rm EXCHANGE [--uri=URI] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap queue create QUEUE [--uri=URI] [--queue-type=TYPE] [--args=KV]...
              [--autodelete] [--transient] [--lazy] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap queue bind QUEUE to EXCHANGE [--uri=URI]
              (--bindingkey=KEY | (--header=KV)... (--all|--any)) [TLSOPTIONS] [COMMON OPTIONS]
  rabtap queue unbind QUEUE from EXCHANGE [--uri=URI]
              (--bindingkey=KEY | (--header=KV)... (--all|--any)) [TLSOPTIONS] [COMMON OPTIONS]
  rabtap queue rm QUEUE [--uri=URI] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap queue purge QUEUE [--uri=URI] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap conn close CONNECTION [--api=APIURI] [--reason=REASON] [TLSOPTIONS] [COMMON OPTIONS]
  rabtap --version
  rabtap (-h | --help | help) [properties]


Arguments and options:
 EXCHANGES            comma-separated list of exchanges and optional binding keys,
                      e.g. 'amq.topic:#' or 'exchange1:key1,exchange2:key2'
 EXCHANGE             name of an exchange, e.g. 'amq.direct'
 DESTEXCHANGE         name of a a destination exchange in an exchange-to-exchange binding
 SOURCE               file or directory to publish in pub mode. If omitted, stdin will be read
 QUEUE                name of a queue
 CONNECTION           name of a connection
 DIR                  directory to read messages from
 DURATION             a numerical duration with a unit suffix like "ms", "s", "m", "h"
 -a, --autodelete     create auto delete exchange/queue
 --all                set x-match=all option in header based routing
 --any                set x-match=any option in header based routing
 --api=APIURI         connect to given API server. If APIURL is omitted, the environment
                      variable RABTAP_APIURI will be used
 --args=KV            A key value pair in the form of "key=value" passed as additional
                      arguments. e.g. '--args=x-queue-type=quorum'
 -b, --bindingkey=KEY binding key to use in bind queue command
 --by-connection      output of info command starts with connections
 --confirms           enable publisher confirms and wait for confirmations
 --consumers          include consumers and connections in output of info command
 --delay=DURATION     Time to wait between sending messages during publish. If not set,
                      then messages will be delayed as recorded.
 --exchange=EXCHANGE  optional exchange to publish to. If omitted, exchange will be taken
                      from message being published (see JSON message format)
 --filter=EXPR        Predicate for sub, tap, info command to filter the output [default: true]
 --format=FORMAT      for tap, pub, sub command: format to write/read messages to console
                        and optionally to file (when --saveto DIR is given).
                        Valid options are: 'raw', 'json', 'json-nopp'. Default: 'raw'
                      for info command: controls generated output format. Valid options
                        are: 'text', 'dot'. Default: 'text'
 -h, --help           prints this help
 --header=KV          A key value pair in the form of "key=value" used as a routing- or
                      binding-key. Can occur multiple times
 --idle-timeout=DURATION end reading messages when no new message was received for the
                      given duration
 -j, --json           deprecated. Use "--format=json" instead
 --lazy               create a lazy queue
 --limit=NUM          Stop afer NUM messages were received. When set to 0, will run until
                      terminated [default: 0]
 --mandatory          enable mandatory publishing (messages must be delivered to queue)
 --mode=MODE          mode for info command. One of 'byConnection', 'byExchange' [default: byExchange]
 --omit-empty         don't show echanges without bindings in info command
 --offset=OFFSET      Offset when reading from a stream. Can be 'first', 'last', 'next',
                      a DURATION like '10m', a RFC3339-Timestamp or an integer index value.
                      Basically it is an alias for '--args=x-stream-offset=OFFSET'
 --property=KV        A key value pair in the form of "key=value" to specify message properties
                      like e.g. the content-type.
 --queue-type=TYPE    type of queue [default: classic]
 --reason=REASON      reason why the connection was closed [default: closed by rabtap]
 --reject             Reject messages. Default behaviour is to acknowledge messages
 --requeue            Instruct broker to requeue rejected message
 -r, --routingkey=KEY routing key to use in publish mode. If omitted, routing key
                      will be taken from message being published (see JSON message format)
 --saveto=DIR         also save messages and metadata to DIR
 --show-default       include default exchange in output info command
 -s, --silent         suppress message output to stdout
 --speed=FACTOR       Speed factor to use during publish [default: 1.0]
 --stats              include statistics in output of info command
 -t, --type=TYPE      type of exchange [default: fanout]
 --transient          create a transient exchange/queue (default is durable)
 --uri=URI            connect to given AQMP broker. If omitted, the environment variable
                      RABTAP_AMQPURI will be used
 --version            show version information and exit

Common options:
 -c, --color          force colored output
 -n, --no-color       don't colorize output (see also environment variable NO_COLOR)
 -v, --verbose        enable verbose mode

TLS options:
 --tls-cert-file=CERTFILE A Cert file to use for client authentication
 --tls-key-file=KEYFILE   A Key file to use for client authentication
 --tls-ca-file=CAFILE     A CA Cert file to use with TLS
 -k, --insecure           allow insecure TLS connections (disables certificate check)

Examples:
  rabtap tap --uri amqp://guest:guest@localhost/ amq.fanout:
  rabtap tap --uri amqp://guest:guest@localhost/ amq.topic:#,amq.fanout:
  rabtap pub --uri amqp://guest:guest@localhost/ --exchange amq.topic message.json --format=json
  rabtap info --api http://guest:guest@localhost:15672/api

  # use RABTAP_AMQPURI environment variable to specify broker instead of --uri
  export RABTAP_AMQPURI=amqp://guest:guest@localhost:5672/
  rabtap queue create JDQ
  rabtap queue bind JDQ to amq.topic --bindingkey=key
  echo "Hello"| gzip | rabtap pub --exchange amq.topic --routingkey "key" --property ContentType=gzip
  rabtap sub JDQ

  # print only messages that have ".Name == 'JAN'" in their JSON payload
  rabtap sub JDQ --filter="let b=fromJSON(r.toStr(r.body(r.msg))); b.Name == 'JAN'"
  rabtap queue rm JDQ

  # use RABTAP_APIURI environment variable to specify mgmt api uri instead of --api
  export RABTAP_APIURI=http://guest:guest@localhost:15672/api
  rabtap info
  rabtap info --filter "r.binding.Source == 'amq.topic'" --omit-empty
  rabtap conn close "172.17.0.1:40874 -> 172.17.0.2:5672"

  # use RABTAP_TLS_CERTFILE | RABTAP_TLS_KEYFILE | RABTAP_TLS_CAFILE environments variables
  # instead of specifying --tls-cert-file=CERTFILE --tls-key-file=KEYFILE --tls-ca-file=CAFILE
```

### Command overview

Rabtap understands the following commands:

- `tap` - taps to an exchange and receives messages sent to the exchange,
  without affecting actual message delivery (using an exchange-to-exchange
  binding).
- `sub` - subscribes to a queue and consumes from the queue
- `pub` - publish messages to an exchange, optionally with the timing as recorded
- `info` - show broker related info (exchanges, queues, bindings, stats).
- `queue` - create,bind,unbind,remove or purge queues
- `exchange` - create or remove exchanges
- `conn` - close connections

See the below for detailed information.

### Broker URI specification

The specification of the RabbitMQ broker URI follows the [AMQP URI
specification](https://www.rabbitmq.com/uri-spec.html) as implemented by the
[go RabbitMQ client library](https://github.com/streadway/amqp).

Examples:

- `amqp://guest:guest@localhost:5672/`
- `amqps://guest:[email protected]:5671/`
- `amqps://guest:[email protected]:5671/vhost`

Note that according to [RFC3986](https://tools.ietf.org/html/rfc3986) it might be
necessary to escape certain characters like e.g. `?` (%3F) or `#` (%23) as otherwise
parsing of the URI may fail with an error.

#### Authentication

Authentication is either by the username and password provided in the broker
URI as desribed above (RabbitMQ `PLAIN` method), or by mTLS providing a client
certificate and key using the `--tls-key-file`, `--tls-cert-file` options (RabbitMQ
`EXTERNAL` method). If both mTLS and a username and password is provided, then
rabtap will use mTLS and `PLAIN` authentication with the given username and
password.

### Environment variables

Use environment variables to specify standard values for broker and api endpoint.

#### Default RabbitMQ broker

In cases where the URI argument is optional, e.g. `rabtap tap [-uri
URI] exchange ...`, the URI of the RabbitMQ broker can be set with the
environment variable `RABTAP_AMQPURI`. Example:

```console
$ export RABTAP_AMQPURI=amqp://guest:guest@localhost:5672/
$ rabtap tap amq.fanout:
...
```

#### Default RabbitMQ management API endpoint

The default RabbitMQ management API URI can be set using the `RABTAP_APIURI`
environment variable. Example:

```console
$ export RABTAP_APIURI=http://guest:guest@localhost:15672/api
$ rabtap info
...
```

The timeout for API requests against this endpoint can be configured using
the `RABTAP_HTTP_TIMEOUT` environment variable using a
[time.Duration](https://pkg.go.dev/time#ParseDuration) value, e.g.
`export RABTAP_HTTP_TIMEOUT=30s`. The default timeout is `10s`. Increase
the timeout when dealing with brokers with many queues and exchanges, since
otherwise `rabtap info` may run into timeouts.

#### Default RabbitMQ TLS config

The default TLS certificates path can be set using the
`RABTAP_TLS_CERTFILE` and `RABTAP_TLS_KEYFILE` and `RABTAP_TLS_CAFILE`
environments variables. All certificate and key files are expected in PEM
format. Example:

```console
$ export RABTAP_TLS_CERTFILE=/path/to/certs/user.crt
$ export RABTAP_TLS_KEYFILE=/path/to/certs/user.key
$ export RABTAP_TLS_CAFILE =/path/to/certs/ca.crt
$ echo "Hello" | rabtap pub --exchange amq.topic --routingkey "key"
...
```

#### Colored output

Output is colored, when writing to a terminal. This behaviour can be changed:

- set environment variable `NO_COLOR` to disable color output (or set
  `--no-color` option)
- set `--color` option to force colored output

### Command reference and examples

The following examples assume a RabbitMQ broker running on `localhost:5672` and
the management API available on port `localhost:15672`. Easiest way to start
such an instance is by running `docker run -ti --rm -p 5672:5672 -p 15672:15672
rabbitmq:3-management` or similar command to start a RabbitMQ container.

#### Broker info

The `info` command uses the REST API of RabbitMQ to gather and display
topolgy related information from the broker.

The `--mode MODE` option controls how the output is structured. Valid options
for `MODE` are `byExchange` (default) or `byConnection`.

The `--format=FORMAT` option controls the format of generated output. Valid
options are `text` for console text format (default) or `dot` to output the
tree structure in dot format for visualization with graphviz.

The features of an exchange are displayed in square brackets with `D`
(durable), `AD` (auto delete) and `I` (internal). The features of a queue are
displayed in square brackets with `D` (durable), `AD` (auto delete) and `EX`
(exclusive).

If the `--stats` option is enabled, basic statistics are included in the
output.

The `--filter` option allows to filter output. See
[filtering](#filtering-output) section for details. Use the
`--by-connection` to sort output by connection (implies `--consumers`)

Examples (assume that `RABTAP_APIURI` environment variable is set):

- `rabtap info --consumers` - shows virtual hosts exchanges, queues and
  consumers of given broker in a tree view (see [screenshot](#screenshots)).
- `rabtap info --mode=byConnection` - shows virtual hosts, connections,
  consumers and queues of given broker in an tree view.
- `rabtap info --format=dot | dot -T svg > broker.svg` - renders broker info
  into `dot` format and uses graphviz to render a SVG file for final
  visualization.

#### Wire-tapping messages

The `tap` command allows to tap to exchanges and transparently receive the messages
sent to the exchanges. The general form of the tap command is either

```text
rabtap tap EXCHANGES [--uri=URI] [--saveto=DIR] [--format=FORMAT]  [--limit=NUM]
       [--idle-timeout=DURATION] [--filter=EXPR] [-jkncsv]
       [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]
```

or, to connect to multiple brokers simultanously,

```text
rabtap (tap --uri=URI EXCHANGES)... [--saveto=DIR] [--format=FORMAT]  [--limit=NUM]
       [--idle-timeout=DURATION] [--filter=EXPR] [-jkncsv]

Frequently Asked Questions

What is rabtap?

rabtap is a Messaging library for the Go programming language. RabbitMQ swiss army knife cli app

How do I install rabtap?

Install rabtap with the Go module system using `go get jandelgado/rabtap`. Check the repository for the current installation instructions.

What category does rabtap belong to?

rabtap is listed under Messaging, specifically Messaging.

← Back to Messaging