{"id":13413420,"url":"https://github.com/jandelgado/rabtap","last_synced_at":"2025-05-15T10:03:43.564Z","repository":{"id":27947209,"uuid":"110340356","full_name":"jandelgado/rabtap","owner":"jandelgado","description":"RabbitMQ wire tap and swiss army knife","archived":false,"fork":false,"pushed_at":"2025-05-04T19:45:21.000Z","size":1388,"stargazers_count":269,"open_issues_count":5,"forks_count":17,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-05-04T20:36:43.155Z","etag":null,"topics":["amqp","golang","publish","pubsub","rabbitmq","subscribe","tap","testing","wiretap"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jandelgado.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-11-11T11:32:39.000Z","updated_at":"2025-05-04T19:44:23.000Z","dependencies_parsed_at":"2023-02-12T22:01:35.323Z","dependency_job_id":"8667c3a2-f9bd-4ecb-864e-ba9a48141cfa","html_url":"https://github.com/jandelgado/rabtap","commit_stats":{"total_commits":169,"total_committers":8,"mean_commits":21.125,"dds":0.4497041420118343,"last_synced_commit":"e1a1d2f510911f11786c62a289e89f9fcd014acb"},"previous_names":[],"tags_count":52,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jandelgado%2Frabtap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jandelgado%2Frabtap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jandelgado%2Frabtap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jandelgado%2Frabtap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jandelgado","download_url":"https://codeload.github.com/jandelgado/rabtap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254319716,"owners_count":22051072,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amqp","golang","publish","pubsub","rabbitmq","subscribe","tap","testing","wiretap"],"created_at":"2024-07-30T20:01:39.954Z","updated_at":"2025-05-15T10:03:38.234Z","avatar_url":"https://github.com/jandelgado.png","language":"Go","readme":"# rabtap - RabbitMQ wire tap\n\n![Build Status](https://github.com/jandelgado/rabtap/workflows/run%20tests/badge.svg)\n[![Coverage Status](https://coveralls.io/repos/github/jandelgado/rabtap/badge.svg?branch=master)](https://coveralls.io/github/jandelgado/rabtap?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/github.com/jandelgado/rabtap)](https://goreportcard.com/report/github.com/jandelgado/rabtap)\n\nSwiss army knife for RabbitMQ. Tap/Pub/Sub messages, create/delete/bind queues\nand exchanges, inspect broker.\n\n## Contents\n\n\u003c!-- vim-markdown-toc GFM --\u003e\n\n* [Features](#features)\n* [Screenshots](#screenshots)\n    * [Show broker topology](#show-broker-topology)\n    * [Visualize broker topology with graphviz](#visualize-broker-topology-with-graphviz)\n    * [Tap messages](#tap-messages)\n* [Installation](#installation)\n    * [Docker image](#docker-image)\n    * [Pre-compiled binaries](#pre-compiled-binaries)\n    * [Arch Linux](#arch-linux)\n    * [Installation from source](#installation-from-source)\n* [Usage](#usage)\n    * [Command overview](#command-overview)\n    * [Broker URI specification](#broker-uri-specification)\n        * [Authentication](#authentication)\n    * [Environment variables](#environment-variables)\n        * [Default RabbitMQ broker](#default-rabbitmq-broker)\n        * [Default RabbitMQ management API endpoint](#default-rabbitmq-management-api-endpoint)\n        * [Default RabbitMQ TLS config](#default-rabbitmq-tls-config)\n        * [Colored output](#colored-output)\n    * [Command reference and examples](#command-reference-and-examples)\n        * [Broker info](#broker-info)\n        * [Wire-tapping messages](#wire-tapping-messages)\n            * [Tap all messages published or delivered (RabbitMQ FireHose)](#tap-all-messages-published-or-delivered-rabbitmq-firehose)\n                * [Replaying messages from the FireHose exchange](#replaying-messages-from-the-firehose-exchange)\n            * [Connect to multiple brokers](#connect-to-multiple-brokers)\n            * [Message recorder](#message-recorder)\n        * [Subscribe messages](#subscribe-messages)\n        * [Publish messages](#publish-messages)\n        * [Poor mans shovel](#poor-mans-shovel)\n        * [Close connection](#close-connection)\n        * [Exchange commands](#exchange-commands)\n        * [Queue commands](#queue-commands)\n    * [Format specification for tap and sub command](#format-specification-for-tap-and-sub-command)\n    * [JSON message format](#json-message-format)\n    * [Filtering output](#filtering-output)\n        * [Filtering expressions](#filtering-expressions)\n            * [Evaluation context](#evaluation-context)\n            * [Examples](#examples)\n        * [Type reference](#type-reference)\n            * [Exchange type](#exchange-type)\n            * [Queue type](#queue-type)\n            * [Binding type](#binding-type)\n            * [Connection type](#connection-type)\n            * [Channel type](#channel-type)\n            * [Message type](#message-type)\n* [Build from source](#build-from-source)\n    * [Download and build using go install](#download-and-build-using-go-install)\n    * [Build using Makefile and tests](#build-using-makefile-and-tests)\n    * [Experimental WASM/wasip1 port](#experimental-wasmwasip1-port)\n* [Test data generator](#test-data-generator)\n* [Contributing](#contributing)\n* [Author](#author)\n* [Copyright and license](#copyright-and-license)\n\n\u003c!-- vim-markdown-toc --\u003e\n\n## Features\n\n* tap to messages being sent to exchanges using RabbitMQ\n  exchange-to-exchange bindings without affecting actual message delivery (aka _tapping_)\n* display broker related information using the\n  [RabbitMQ REST management API](https://rawcdn.githack.com/rabbitmq/rabbitmq-management/rabbitmq_v3_6_14/priv/www/api/index.html)\n* save messages and meta data for later analysis and replay\n* publish messages to exchanges\n* consume messages from queues and streams (subscribe)\n* filter output using flexible expressions\n* supports TLS\n* no runtime dependencies (statically linked golang single file binary)\n* simple to use command line tool\n* runs on Linux, Windows, Mac and wherever you can compile go\n\n## Screenshots\n\n### Show broker topology\n\nOutput of `rabtap info` command:\n\n![info mode](doc/images/info.png)\n\nOutput of `rabtap info --stats` command, showing additional statistics:\n\n![info mode](doc/images/info-stats.png)\n\n### Visualize broker topology with graphviz\n\nUsing the `--format=dot` option, the `info` command can generate output in the\n[dot format](https://graphviz.org/doc/info/lang.html), which can be visualized\nusing graphviz, e.g. `rabtap info --show-default --format dot | dot -T svg \u003e\nmybroker.svg`. The resulting SVG file can be visualized with a web browser.\n\n![info mode](doc/images/info-dot.png)\n\n### Tap messages\n\nOutput of rabtap in `tap` mode, showing message meta data and the message body:\n\n![info mode](doc/images/tap.png)\n\n## Installation\n\n### Docker image\n\nA docker image is provided so rabtap can be used as a docker container, e.g.\n\n```console\n$ docker run --rm -ti ghcr.io/jandelgado/rabtap:latest\n```\n\n### Pre-compiled binaries\n\nPre-compiled binaries can be downloaded for multiple platforms from the\n[releases page](https://github.com/jandelgado/rabtap/releases).\n\n### Arch Linux\n\nRabtap can be installed from the Arch Linux User Repository (AUR):\n\n```console\n$ yay -S rabtap\n```\n\n### Installation from source\n\nSee the [build from source section](#build-from-source) if you prefer to\ncompile from source.\n\n## Usage\n\n```text\nrabtap - RabbitMQ wire tap.                    github.com/jandelgado/rabtap\n\nUsage:\n  rabtap info [--api=APIURI] [--consumers] [--stats] [--filter=EXPR] [--omit-empty]\n              [--show-default] [--mode=MODE] [--format=FORMAT] [-kncv]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap tap EXCHANGES [--uri=URI] [--saveto=DIR] [--format=FORMAT]  [--limit=NUM]\n\t      [--idle-timeout=DURATION] [--filter=EXPR] [-jkncsv]\n\t      [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap (tap --uri=URI EXCHANGES)... [--saveto=DIR] [--format=FORMAT]  [--limit=NUM]\n\t      [--idle-timeout=DURATION] [--filter=EXPR] [-jkncsv]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap sub QUEUE [--uri URI] [--saveto=DIR] [--format=FORMAT] [--limit=NUM]\n              [--offset=OFFSET] [--args=KV]... [(--reject [--requeue])] [-jkcsvn]\n              [--filter=EXPR] [--idle-timeout=DURATION]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap pub  [--uri=URI] [SOURCE] [--exchange=EXCHANGE] [--format=FORMAT]\n              [--routingkey=KEY | (--header=KV)...] [ (--property=KV)... ]\n              [--confirms] [--mandatory] [--delay=DELAY | --speed=FACTOR] [-jkv]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap exchange create EXCHANGE [--uri=URI] [--type=TYPE] [--args=KV]... [-kv]\n              [--autodelete] [--durable]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap exchange bind EXCHANGE to DESTEXCHANGE [--uri=URI] [-kv]\n              (--bindingkey=KEY | (--header=KV)... (--all|--any))\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap exchange rm EXCHANGE [--uri=URI] [-kv]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap queue create QUEUE [--uri=URI] [--queue-type=TYPE] [--args=KV]... [-kv]\n              [--autodelete] [--durable] [--lazy]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap queue bind QUEUE to EXCHANGE [--uri=URI] [-kv]\n              (--bindingkey=KEY | (--header=KV)... (--all|--any))\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap queue unbind QUEUE from EXCHANGE [--uri=URI] [-kv]\n              (--bindingkey=KEY | (--header=KV)... (--all|--any))\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap queue rm QUEUE [--uri=URI] [-kv]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap queue purge QUEUE [--uri=URI] [-kv]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap conn close CONNECTION [--api=APIURI] [--reason=REASON] [-kv]\n              [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n  rabtap --version\n  rabtap (-h | --help | help) [properties]\n\nArguments and options:\n EXCHANGES            comma-separated list of exchanges and optional binding keys,\n                      e.g. amq.topic:# or exchange1:key1,exchange2:key2.\n EXCHANGE             name of an exchange, e.g. amq.direct.\n DESTEXCHANGE         name of a a destination exchange in an exchange-to-exchange binding.\n SOURCE               file or directory to publish in pub mode. If omitted, stdin will be read.\n QUEUE                name of a queue.\n CONNECTION           name of a connection.\n DIR                  directory to read messages from.\n -a, --autodelete     create auto delete exchange/queue.\n --all                set x-match=all option in header based routing.\n --any                set x-match=any option in header based routing.\n --api=APIURI         connect to given API server. If APIURL is omitted,\n                      the environment variable RABTAP_APIURI will be used.\n --args=KV            A key value pair in the form of \"key=value\" passed as\n                      additional arguments. e.g. '--args=x-queue-type=quorum'\n -b, --bindingkey=KEY binding key to use in bind queue command.\n --by-connection      output of info command starts with connections.\n -c, --color          force colored output\n --confirms           enable publisher confirms and wait for confirmations.\n --consumers          include consumers and connections in output of info command.\n --delay=DELAY        Time to wait between sending messages during publish.\n                      If not set then messages will be delayed as recorded.\n                      The value must be suffixed with a time unit, e.g. ms, s etc.\n -d, --durable        create durable exchange/queue.\n --exchange=EXCHANGE  Optional exchange to publish to. If omitted, exchange will\n                      be taken from message being published (see JSON message format).\n --filter=EXPR        Predicate for sub, tap, info command to filter the output [default: true]\n --format=FORMAT      * for tap, pub, sub command: format to write/read messages to console\n                        and optionally to file (when --saveto DIR is given).\n                        Valid options are: \"raw\", \"json\", \"json-nopp\". Default: raw\n                      * for info command: controls generated output format. Valid\n                        options are: \"text\", \"dot\". Default: text\n -h, --help           print this help\n --header=KV          A key value pair in the form of \"key=value\" used as a\n                      routing- or binding-key. Can occur multiple times.\n --idle-timeout=DURATION end reading messages when no new message was received\n                      for the given duration.  The value must be suffixed with\n                      a time unit, e.g. ms, s etc.\n -j, --json           deprecated. Use \"--format json\" instead.\n -k, --insecure       allow insecure TLS connections (no certificate check).\n --lazy               create a lazy queue.\n --limit=NUM          Stop afer NUM messages were received. When set to 0, will\n                      run until terminated [default: 0].\n --mandatory          enable mandatory publishing (messages must be delivered to queue).\n --mode=MODE          mode for info command. One of \"byConnection\", \"byExchange\".\n                      [default: byExchange].\n -n, --no-color       don't colorize output (see also environment variable NO_COLOR).\n --omit-empty         don't show echanges without bindings in info command.\n --offset=OFFSET      Offset when reading from a stream. Can be 'first', 'last',\n                      'next', a duration like '10m', a RFC3339-Timestamp or\n                      an integer index value. Basically it is an alias for\n                      '--args=x-stream-offset=OFFSET'.\n --property=KV        A key value pair in the form of \"key=value\" to specify\n\t              message properties like e.g. the content-type.\n --queue-type=TYPE    type of queue [default: classic].\n --reason=REASON      reason why the connection was closed [default: closed by rabtap].\n --reject             Reject messages. Default behaviour is to acknowledge messages.\n --requeue            Instruct broker to requeue rejected message\n -r, --routingkey=KEY routing key to use in publish mode. If omitted, routing key\n                      will be taken from message being published (see JSON\n                      message format).\n --saveto=DIR         also save messages and metadata to DIR.\n --show-default       include default exchange in output info command.\n -s, --silent         suppress message output to stdout.\n --speed=FACTOR       Speed factor to use during publish [default: 1.0].\n --stats              include statistics in output of info command.\n -t, --type=TYPE      type of exchange [default: fanout].\n --tls-cert-file=CERTFILE A Cert file to use for client authentication.\n --tls-key-file=KEYFILE   A Key file to use for client authentication.\n --tls-ca-file=CAFILE     A CA Cert file to use with TLS.\n --uri=URI            connect to given AQMP broker. If omitted, the\n                      environment variable RABTAP_AMQPURI will be used.\n -v, --verbose        enable verbose mode.\n --version            show version information and exit.\n\nExamples:\n  rabtap tap --uri amqp://guest:guest@localhost/ amq.fanout:\n  rabtap tap --uri amqp://guest:guest@localhost/ amq.topic:#,amq.fanout:\n  rabtap pub --uri amqp://guest:guest@localhost/ --exchange amq.topic message.json --format=json\n  rabtap info --api http://guest:guest@localhost:15672/api\n\n  # use RABTAP_AMQPURI environment variable to specify broker instead of --uri\n  export RABTAP_AMQPURI=amqp://guest:guest@localhost:5672/\n  rabtap queue create JDQ\n  rabtap queue bind JDQ to amq.topic --bindingkey=key\n  echo \"Hello\"| gzip | rabtap pub --exchange amq.topic --routingkey \"key\" --property ContentType=gzip\n  rabtap sub JDQ\n\n  # print only messages that have \".Name == 'JAN'\" in their JSON payload\n  rabtap sub JDQ --filter=\"let b=fromJSON(r.toStr(r.body(r.msg))); b.Name == 'JAN'\"\n  rabtap queue rm JDQ\n\n  # use RABTAP_APIURI environment variable to specify mgmt api uri instead of --api\n  export RABTAP_APIURI=http://guest:guest@localhost:15672/api\n  rabtap info\n  rabtap info --filter \"r.binding.Source == 'amq.topic'\" --omit-empty\n  rabtap conn close \"172.17.0.1:40874 -\u003e 172.17.0.2:5672\"\n\n  # use RABTAP_TLS_CERTFILE | RABTAP_TLS_KEYFILE | RABTAP_TLS_CAFILE environments variables\n  # instead of specifying --tls-cert-file=CERTFILE --tls-key-file=KEYFILE --tls-ca-file=CAFILE\n```\n\n### Command overview\n\nRabtap understands the following commands:\n\n* `tap` - taps to an exchange and receives messages sent to the exchange,\n   without affecting actual message delivery (using an exchange-to-exchange\n   binding).\n* `sub` - subscribes to a queue and consumes from the queue\n* `pub` - publish messages to an exchange, optionally with the timing as recorded\n* `info` - show broker related info (exchanges, queues, bindings, stats).\n* `queue` - create,bind,unbind,remove or purge queues\n* `exchange` - create or remove exchanges\n* `conn` - close connections\n\nSee the below for detailed information.\n\n### Broker URI specification\n\nThe specification of the RabbitMQ broker URI follows the [AMQP URI\nspecification](https://www.rabbitmq.com/uri-spec.html) as implemented by the\n[go RabbitMQ client library](https://github.com/streadway/amqp).\n\nExamples:\n* `amqp://guest:guest@localhost:5672/`\n* `amqps://guest:guest@my-broker.dev:5671/`\n* `amqps://guest:guest@my-broker.dev:5671/vhost`\n\nNote that according to [RFC3986](https://tools.ietf.org/html/rfc3986) it might be\nnecessary to escape certain characters like e.g. `?` (%3F) or `#` (%23) as otherwise\nparsing of the URI may fail with an error.\n\n#### Authentication\n\nAuthentication is either by the username and password provided in the broker\nURI as desribed above (RabbitMQ `PLAIN` method), or by mTLS providing a client\ncertificate and key using the `--tls-key-file`, `--tls-cert-file` options (RabbitMQ\n`EXTERNAL` method). If both mTLS and a username and password is provided, then\nrabtap will use mTLS and `PLAIN` authentication with the given username and\npassword.\n\n### Environment variables\n\nUse environment variables to specify standard values for broker and api endpoint.\n\n#### Default RabbitMQ broker\n\nIn cases where the URI argument is optional, e.g. `rabtap tap [-uri\nURI] exchange ...`, the URI of the RabbitMQ broker can be set with the\nenvironment variable `RABTAP_AMQPURI`.  Example:\n\n```console\n$ export RABTAP_AMQPURI=amqp://guest:guest@localhost:5672/\n$ rabtap tap amq.fanout:\n...\n```\n\n#### Default RabbitMQ management API endpoint\n\nThe default RabbitMQ management API URI can be set using the `RABTAP_APIURI`\nenvironment variable. Example:\n\n```console\n$ export RABTAP_APIURI=http://guest:guest@localhost:15672/api\n$ rabtap info\n...\n```\n\nThe timeout for API requests against this endpoint can be configured using\nthe `RABTAP_HTTP_TIMEOUT` environment variable using a\n[time.Duration](https://pkg.go.dev/time#ParseDuration) value, e.g.\n`export RABTAP_HTTP_TIMEOUT=30s`. The default timeout is `10s`. Increase\nthe timeout when dealing with brokers with many queues and exchanges, since\notherwise `rabtap info` may run into timeouts.\n\n#### Default RabbitMQ TLS config\n\nThe default TLS certificates path can be set using the\n`RABTAP_TLS_CERTFILE` and `RABTAP_TLS_KEYFILE` and `RABTAP_TLS_CAFILE`\nenvironments variables. All certificate and key files are expected in PEM\nformat. Example:\n\n```console\n$ export RABTAP_TLS_CERTFILE=/path/to/certs/user.crt\n$ export RABTAP_TLS_KEYFILE=/path/to/certs/user.key\n$ export RABTAP_TLS_CAFILE =/path/to/certs/ca.crt\n$ echo \"Hello\" | rabtap pub --exchange amq.topic --routingkey \"key\"\n...\n```\n\n#### Colored output\n\nOutput is colored, when writing to a terminal. This behaviour can be changed:\n\n* set environment variable `NO_COLOR` to disable color output (or set\n  `--no-color` option)\n* set `--color` option to force colored output\n\n### Command reference and examples\n\nThe following examples assume a RabbitMQ broker running on `localhost:5672` and\nthe management API available on port `localhost:15672`. Easiest way to start\nsuch an instance is by running `docker run -ti --rm -p 5672:5672 -p 15672:15672\nrabbitmq:3-management` or similar command to start a RabbitMQ container.\n\n#### Broker info\n\nThe `info` command uses the REST API of RabbitMQ to gather and display\ntopolgy related information from the broker.\n\nThe `--mode MODE` option controls how the output is structured. Valid options\nfor `MODE` are `byExchange` (default) or `byConnection`.\n\nThe `--format=FORMAT` option controls the format of generated output. Valid\noptions are `text` for console text format (default) or `dot` to output the\ntree structure in dot format for visualization with graphviz.\n\nThe features of an exchange are displayed in square brackets with `D`\n(durable), `AD` (auto delete) and `I` (internal). The features of a queue are\ndisplayed in square brackets with `D` (durable), `AD` (auto delete) and `EX`\n(exclusive).\n\nIf the `--stats` option is enabled, basic statistics are included in the\noutput.\n\nThe `--filter` option allows to filter output. See\n[filtering](#filtering-output) section for details. Use the\n`--by-connection` to sort output by connection (implies `--consumers`)\n\nExamples (assume that `RABTAP_APIURI` environment variable is set):\n\n* `rabtap info --consumers` - shows virtual hosts exchanges, queues and\n  consumers of given broker in a tree view (see [screenshot](#screenshots)).\n* `rabtap info --mode=byConnection` - shows virtual hosts, connections,\n  consumers and queues of given broker in an tree view.\n* `rabtap info --format=dot | dot -T svg \u003e broker.svg` - renders broker info\n  into `dot` format and uses graphviz to render a SVG file for final\n  visualization.\n\n#### Wire-tapping messages\n\nThe `tap` command allows to tap to exchanges and transparently receive the messages\nsent to the exchanges.  The general form of the tap command is either\n\n```text\nrabtap tap EXCHANGES [--uri=URI] [--saveto=DIR] [--format=FORMAT]  [--limit=NUM]\n       [--idle-timeout=DURATION] [--filter=EXPR] [-jkncsv]\n       [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n```\n\nor, to connect to multiple brokers simultanously,\n\n```text\nrabtap (tap --uri=URI EXCHANGES)... [--saveto=DIR] [--format=FORMAT]  [--limit=NUM]\n       [--idle-timeout=DURATION] [--filter=EXPR] [-jkncsv]\n       [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n```\n\nThe `EXCHANGES` argument specifies the exchanges and binding keys to use.\nThe `EXCHANGES` argument is of the form `EXCHANGE:[KEY][,EXCHANGE:[KEY]]*`. If\nthe exchange name contains a colon, use `\\\\:` to escape it, e.g.\n`myexchange\\\\:with\\\\:colons:KEY`.\n\nThe acutal format of the binding key depends on the exchange type (e.g.\ndirect, topic, headers) and is described in the [RabbitMQ\ndocumentation](https://www.rabbitmq.com/tutorials/amqp-concepts.html).\n\nWhen `--saveto=DIR` is set, received messages will be written to the specified\ndirectory. The `--formate=FORMAT` option controls the format of output both on\nthe console as well as in the written files (see\n[below](#format-specification-for-tap-and-sub-command) for details).\n\nThe `--filter EXPR` allows filtering of messages using an expression language.\nSee [Filtering](#filtering-output) for details and examples.\n\nUse the `--limit=NUM` option to limit the number of received messages. If\nspecified, rabtap will terminate, after `NUM` messages were read and passed\nthe filter (if set).\n\nWhen `--idle-timeout=DURATION` is set, the subscribe command will terminate\nwhen no new messages were received in the given time period. Look for the\ndescription of the `--delay` option for the format of the `DURATION` parameter.\n\nExamples for binding keys used in `tap` command:\n\n* `#` on  an exchange of type `topic` will make the tap receive all messages\n  on the exchange.\n* a valid queue name for an exchange of type `direct` binds exactly to messages\n  destined for this queue\n* an empty binding key for exchanges of type `fanout` or type `headers` will\n  receive all messages published to these exchanges\n\nNote: on exchanges of type `headers` the binding key is currently ignored and\nall messages are received by the tap.\n\nThe following examples assume that the `RABTAP_AMQPURI` environment variable is\nset, otherwise you have to pass the additional `--uri URI` parameter to the\ncommands below.\n\n* `$ rabtap tap my-topic-exchange:#`\n* `$ rabtap tap my-fanout-exchange:`\n* `$ rabtap tap my-headers-exchange:`\n* `$ rabtap tap my-direct-exchange:binding-key`\n\nThe following example connects to multiple exchanges:\n\n* `$ rabtap tap my-fanout-exchange:,my-topic-exchange:#,my-other-exchange:binding-key`\n\n##### Tap all messages published or delivered (RabbitMQ FireHose)\n\nThe [RabbitMQ Firehose Tracer](https://www.rabbitmq.com/firehose.html) allows\nto \"see\" every message that is published or delivered. To use it, the FireHose\ntracer has to be enabled first:\n\n```text\n$ rabbitmqctl trace_on\n```\n\nAfterwards, every message published or delivered will be CC'd to the topic\nexhange `amq.rabbitmq.trace`.  The messages can now be tapped with rabtap:\n\n```text\n$ rabtap --uri amqp://guest:guest@localhost:5672/ tap amq.rabbitmq.trace:published.#\n```\n\nRabbitMQ sends all messages published or delivered to the FireHose exchange.\nPublished messages are sent with the routing key `publish.{exchangename}`, while\ndelivered messages are sent with the routing key `deliver.{queuename}`.\nDepending on what you want to record, specify your binding accordingly.\n\n###### Replaying messages from the FireHose exchange\n\nWhen messages are tapped or subscribed from the FireHose tracer exchange, these\nmessages have the original meta data stored in the headers section of the\nmessage. When published later, rabtap detects that these message was recorded\nfrom the FireHose (by examining the `exchange` attribute, which will be set to\n`amq.rabbitmq.trace` by RabbitMQ in that case) and automatically transform the\nmessage so that the originally published messages are replayed again.\n\n##### Connect to multiple brokers\n\nRabtap allows you also to connect simultaneously to multiple brokers and\nexchanges:\n\n```text\n$ rabtap tap --uri amqp://broker1 amq.topic:# tap --uri amqp://broker2 amq.fanout:\n```\n\nThe example connects to `broker1` and taps to the `amq.topic` exchange and to\nthe `amq.fanout` exchange on `broker2`.\n\n##### Message recorder\n\nAll tapped messages can be also be saved for later analysis or replay. Rabtap\nsupports saving of messages in two formats: raw body and metadata in separate\nfiles or [JSON message format](#json-message-format) with embedded metadata and\nmessage the body base64 encode. Examples:\n\n* `$ rabtap tap amq.topic:# --saveto /tmp` - saves messages as pair of\n  files consisting of raw message body and JSON meta data file to `/tmp`\n  directory.\n* `$ rabtap tap amq.topic:# --saveto /tmp --format json` - saves messages as\n  JSON files to `/tmp` directory.\n\nFiles are created with file name `rabtap-`+`\u003cUnix-Nano-Timestamp\u003e`+ `.` +\n`\u003cextension\u003e`.\n\n#### Subscribe messages\n\nThe `sub` command reads messages from a queue or a stream. The general form\nof the `sub` command is:\n\n```text\nrabtap sub QUEUE [--uri URI] [--saveto=DIR] [--format=FORMAT] [--limit=NUM]\n       [--offset=OFFSET] [--args=KV]... [(--reject [--requeue])] [-jkcsvn]\n       [--filter=EXPR] [--idle-timeout=DURATION]\n       [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n```\n\nUse the `--reject` option to 'nack' messages, which in turn will be discarded\nby the broker or routed to a configured dead letter exchange (DLX). if\n`--requeue` is also set, the message will be returned to the queue.\n\nThe `--offset=OFFSET` option is used when subscribing to streams. Streams are\nappend-only data structures with non-destructive semantics and were introduced\nwith RabbitMQ 3.9. The `OFFSET` parameter specifies where to start reading from the\nstream and must be any of: `first`, `last`, `next`, a numerical offset, a\nRFC3339-Timestamp or a duration specification like `10m`. Consult the RabbitMQ\ndocumentation for more information on [streams](https://www.rabbitmq.com/streams.html).\n\nWhen `--idle-timeout=DURATION` is set, the subscribe command will terminate\nwhen no new messages were received in the given time period. Look for the\ndescription of the `--delay` option for the format of the `DURATION` parameter.\n\nRefer to the `tap` command for a description of the `--filter=EXPR`,\n`--limit=NUM`, `--saveto=DIR` and `--format=FORMAT`  options.\n\nExamples:\n\n* `rabtap sub somequeue --format=json` - will consume messages from queue\n  `somequeue` and print out messages in JSON format. The Example assumes that\n  `RABTAP_AMQPURI` environment variable is set, as the `--uri=AMQPURI`\n  parameter is omitted\n* `rabtap sub somequeue --limit=1 --reject --requeue` - consume one message\n  from the queue `somequeue`, then exit, and let the broker requeue the message\n* `rabtap sub mystream --offset=first` - read all messages from the stream\n  `mystream`\n* `rabtap sub mystream --offset=50` - read messages from stream `mystream`\n  starting with the 50th message\n* `rabtap sub mystream --offset=10m` - read messages from stream `mystream`\n  which are aged 10 minutes or less\n* `rabtap sub somequeue --idle-timeout=5s` - read messages from queue `somequeue`\n  and exit when there is no new message received for 5 seconds\n\n#### Publish messages\n\nThe `pub` command is used to publish messages to an exchange.  The general\nform of the `pub` command is:\n\n```text\nrabtap pub  [--uri=URI] [SOURCE] [--exchange=EXCHANGE] [--format=FORMAT]\n            [--routingkey=KEY | (--header=KV)...] [ (--property=KV)... ]\n            [--confirms] [--mandatory] [--delay=DELAY | --speed=FACTOR] [-jkv]\n            [(--tls-cert-file=CERTFILE --tls-key-file=KEYFILE)] [--tls-ca-file=CAFILE]\n```\n\nThe `SOURCE` parameter specifies the messages to be published. These are either\nread from a file, or from a directory which contains previously recorded\nmessages (e.g. using the `--saveto` option of the `tap` command).  If `SOURCE`\nis omitted, `stdin` is used.\n\nMessage routing is either specified with a routing key and the `--routingkey`\noption or, when header based routing should be used, by specifying the headers\nwith the `--header` option. Each header is specified in the form `KEY=VALUE`.\nMultiple headers can be specified by specifying multiple `--header` options.\n\nMessages can be published either in raw format, in which they are sent as-is,\nor in [JSON-format, as described here](#json-message-format) (`--format=json`),\nwhich includes message metadata and the body in a single JSON document. When\nmultiple messages are published with metadata, rabtap will calculate the time\nelapsed of consecutive recorded messages using the metadata, and delay\npublishing accordingly.\n\nTo set the publishing delay to a fix value, use the `--delay` option. To\npublish without delays, use `--delay=0s`. To modify publishing speed use the\n`--speed` option, which allows to set a factor to apply to the delays. A delay\nis a sequence of decimal numbers, each with optional fraction and a unit\nsuffix, such as `300ms`, `-1.5h` or `2h45m`. Valid time units are `ns`, `us`\n(or `µs`), `ms`, `s`, `m`, `h`.\n\nWhen the `--confirms` option is set, rabtap waits for publisher confirmations\nfrom the server and logs an error if a confirmation is negative or not received\n(slows down throughput),\n\nWhen the `--mandatory` option is set, rabtap publishes message in mandatory\nmode. If set and a message can not be delivered to a queue, the server returns\nthe message and rabtap will log an error.\n\nUse the `--property` option to set message properties like `ContentType` etc.\nMultiple properties can be specified by specifying multiple `--property` options.\nRun `rabtap help properties` to see the list of available properties:\n\n```text\nDeliveryMode    - delivery mode: 'transient' or 'persistent'\nPriority        - message priority for priority queues\nExpiration      - message TTL (ms)\nContentType     - application use - MIME content type\nContentEncoding - application use - MIME content encoding\nCorrelationId   - application use - correlation identifier\nReplyTo         - application use - address to reply to\nMessageId       - application use - message identifier\nTimestamp       - application use - RFC3339 message timestamp\nType            - application use - message type name\nAppId           - application use - creating application id\nUserId          - user id, validated if set\n```\n\nExamples:\n\n* `echo hello | rabtap pub --exchange amq.fanout` - publish \"hello\" to\n  exchange amqp.fanout\n* `echo \"hello\" | rabtap pub --exchange amq.header --header KEY=VAL --header X=Y` -\n  publish `hello` to exchange `amq.header` and set given message headers\n* `rabtap pub messages.json --format=json`  - messages are read from file\n  `messages.json` in [rabtap JSON format](#json-message-format). Target\n  exchange and routing keys are read from the messages meta data.  The\n  `messages.json` file can contain multiple JSON documents as it is treated as\n  a JSON stream.  Rabtap will honor the `XRabtapReceived` timestamps of the\n  messages and by default will delay the messages as they were recorded. This\n  behaviour can be overridden by the `--delay` and `--speed` options\n* `rabtap pub --exchange amq.direct -r myKey --format=json messages.json --delay=0s` - as\n  before, but publish messages always to exchange `amq.direct` with routing key\n  `myKey` and without any delays\n* `rabtap pub --exchange amq.direct -r myKey --format=raw somedir --delay=0s` - as\n  before, but assuming that `somedir` is a directory, the messages are read\n  from message files previously recorded to this directory and replayed in the\n  order they were recorded\n* `echo hello | rabtap pub --exchange amq.fanout --property Expiration=1000` -\n   publish `hello` to exchange `amq.fanout` and set the message expiration to 1000ms.\n* `echo hello | gzip | rabtap pub --exchange amq.fanout --property ContentEncoding=gzip` -\n   publish gzip compressed `hello` to exchange `amq.fanout` and set the `ContentEncoding`\n   message property accordingly.\n\n#### Poor mans shovel\n\nRabtap instances can be linked through a pipe and messages will be read on\none side and published to the other. Note that for publish to work in streaming\nmode, the JSON mode (`--format json`) must be used on both sides, so that\nmessages are encapsulated in JSON messages.\n\nThe example taps messages on `broker1` and publishes the messages to the\n`amq.direct` exchange on `broker2`\n\n```console\n$ rabtap tap --uri amqp://broker1 my-topic-exchange:# --format json | \\\n  rabtap pub --uri amqp://broker2 --exchange amq.direct -r routingKey --format json\n```\n\n#### Close connection\n\nThe `conn` command allows to close a connection. The name of the connection to\nbe closed is expected as parameter. Use the `info` command with the\n`--consumers` option to find the connection associated with a queue. Example:\n\n```console\n$ rabtap info --consumers\nhttp://localhost:15672/api (broker ver='3.6.9', mgmt ver='3.6.9', cluster='rabbit@ae1ad1477419')\n└── Vhost /\n    ├── amq.direct (exchange, type 'direct', [D])\n    :\n    └── test-topic (exchange, type 'topic', [AD])\n        ├── test-q-test-topic-0 (queue, key='test-q-test-topic-0', running, [])\n        │   └── __rabtap-consumer-4823a3c0 (consumer user='guest', chan='172.17.0.1:59228 -\u003e 172.17.0.2:5672 (1)')\n        │       └── '172.17.0.1:59228 -\u003e 172.17.0.2:5672' (connection client='https://github.com/streadway/amqp', host='172.17.0.2:5672', peer='172.17.0.1:59228')\n        ├── test-q-test-topic-1 (queue, key='test-q-test-topic-1', running, [])\n        :\n$ rabtap conn close '172.17.0.1:59228 -\u003e 172.17.0.2:5672'\n```\n\n#### Exchange commands\n\nThe `exchange` command is used to create, remove and bind exchanges:\n\n```text\n$ rabtap exchange create myexchange --type topic\n$ rabtap exchange rm myexchange\n```\n\nThe `create` commands allows to specify additional arguments to be passed to\nRabbitMQ using the `--args=key=value` syntax:\n\n```text\n$ rabtap exchange create myexchange --type topic --args=alternate-exchange=myae\n```\n\nThe `bind` command creates an exchange-to-exchange binding (similar to a\nqueue-to-exchange binding):\n\n```text\n$ rabtap exchange bind myechange to destexchange --bindingkey=KEY\n```\n\n#### Queue commands\n\nThe `queue` command is used to create, remove, bind or unbind queues:\n\n```text\n$ rabtap queue create myqueue\n$ rabtap info --show-default\nhttp://localhost:15672/api (broker ver='3.7.8', mgmt ver='3.7.8', cluster='rabbit@b2fe3b3b6826')\n└── Vhost /\n    ├── (default) (exchange, type 'direct', [D])\n    │   └── myqueue (queue, key='myqueue', idle since 2018-12-07 20:46:15, [])\n    :\n    └── amq.topic (exchange, type 'topic', [D])\n$ rabtap queue bind myqueue to amq.topic --bindingkey hello\n$ rabtap info --show-default\nhttp://localhost:15672/api (broker ver='3.7.8', mgmt ver='3.7.8', cluster='rabbit@b2fe3b3b6826')\n└── Vhost /\n    ├── (default) (exchange, type 'direct', [D])\n    │   └── myqueue (queue, key='myqueue', idle since 2018-12-07 20:46:15, [])\n    :\n    └── amq.topic (exchange, type 'topic', [D])\n        └── myqueue (queue, key='hello', idle since 2018-12-07 20:46:15, [])\n$ rabtap queue unbind myqueue from amq.topic --bindingkey hello\n$ rabtap info --show-default\nhttp://localhost:15672/api (broker ver='3.7.8', mgmt ver='3.7.8', cluster='rabbit@b2fe3b3b6826')\n└── Vhost /\n    ├── (default) (exchange, type 'direct', [D])\n    │   └── myqueue (queue, key='myqueue', idle since 2018-12-07 20:46:15, [])\n    :\n    └── amq.topic (exchange, type 'topic', [D])\n$ rabtap queue purge myqueue\n$ rabtap queue rm myqueue\n$ rabtap info\nhttp://localhost:15672/api (broker ver='3.7.8', mgmt ver='3.7.8', cluster='rabbit@b2fe3b3b6826')\n└── Vhost /\n    :\n    └── amq.topic (exchange, type 'topic', [D])\n```\n\nThe `create` commands allows to specify additional arguments to be passed to\nRabbitMQ using the `--args=key=value` syntax. This allows for example to specify\nthe queue type or mode:\n\n* `rabtap queue create quorum_queue --args=x-queue-type=quorum --durable` -\n  create a quorum queue named `quorum_queue`. The same can be achieved by using\n  the `--queue-type` option, which is an alias for setting the arg `x-queue-type`:\n  `rabtap queue create quorum --queue-type=quorum --durable`\n* `rabtap queue create mystream --queue-type=stream --durable` - create a stream\n* `rabtap queue create lazy_queue --lazy` - create a classic queue in lazy\n  mode that is named `lazy_queue`. `--lazy` is an alias for setting the arg\n  `x-queue-mode`\n\n### Format specification for tap and sub command\n\nThe `--format=FORMAT` option controls the format of the `tap` and `sub`\ncommands when writing messages to the console and optionally to the filesystem\n(i.e.  when `--saveto=DIR` is set). The `FORMAT` parameter has the following\neffect on the output:\n\n| `FORMAT`        | Format on console                            | Format of saved messages (`--saveto DIR`)    |\n|-----------------|----------------------------------------------|----------------------------------------------|\n| `raw` (default) | Pretty-printed metadata + raw Message body   | Metadata as JSON-File + Body as-is           |\n| `json`          | Pretty-printed JSON wiht base64 encoded body | Pretty-printed JSON with base64 encoded body |\n| `json-nopp`     | Single line JSON wiht base64 encoded body    | Pretty-printed JSON with base64 encoded body |\n\nNotes:\n\n* the `--json` option is now deprecated. Use `--format=json` instead\n* `nopp` stands for `no pretty-print`\n* When the message body is output on the console in `raw` format, Rabtap takes the\n `ContentEncoding` property into account and decompresses the body if necessary.\n Currently supported encodings are gzip, deflate, zstd, and bzip2.\n\n### JSON message format\n\nWhen using the `--format json` option, messages are print/read as a stream of JSON\nmessages in the following format:\n\n```json\n{\n  \"ContentType\": \"text/plain\",\n  \"ContentEncoding\": \"\",\n  \"DeliveryMode\": 0,\n  \"Priority\": 0,\n  \"CorrelationID\": \"\",\n  \"ReplyTo\": \"\",\n  \"Expiration\": \"\",\n  \"MessageID\": \"\",\n  \"Timestamp\": \"2017-11-10T00:13:38+01:00\",\n  \"Type\": \"\",\n  \"UserID\": \"\",\n  \"AppID\": \"rabtap.testgen\",\n  \"DeliveryTag\": 27,\n  \"Redelivered\": false,\n  \"Exchange\": \"amq.topic\",\n  \"RoutingKey\": \"test-q-amq.topic-0\",\n  \"XRabtapReceivedTimestamp\": \"2019-06-13T19:33:51.920711583+02:00\",\n  \"Body\": \"dGhpcyB0ZXN0IG1lc3NhZ2U .... IGFuZCBoZWFkZXJzIGFtcXAuVGFibGV7fQ==\"\n}\n```\n\nNote that in JSON mode, the `Body` is base64 encoded.\n\n### Filtering output\n\nWhen your brokers topology is complex, the output of the `info` command can\nbecome very bloated. The `--filter` helps you to narrow output to the desired\ninformation. The same filtering mechanism can be applied to the `tap` and `sub`\ncommands to filter only messages of interest.\n\n#### Filtering expressions\n\nA filtering expression is a function that evaluates to `true` or `false` (i.e.\na _predicate_). When a filter is used, output will be supressed, if the predicate\nevalautes to `false`.\n\nRabtap uses [Expr](https://expr-lang.org/) to evaluate predicates. This allows\nfor complex expressions. See the [official expr-lang\ndocumentation](https://expr-lang.org/docs/language-definition) for further\ninformation.\n\n\u003e Note: prior to version 1.40, rabtap used\n\u003e [govaluate](https://github.com/Knetic/govaluate) to evaluate expressions.\n\u003e With the switch to [Expr](https://expr-lang.org/), the syntax has changed in\n\u003e some aspects (e.g. `=~` vs `matches`  in regular expression matches). Consult\n\u003e the documentation for details.\n\n##### Evaluation context\n\nDuring evaluation, the context (i.e. the current exchange, queue, etc.)\nis made available to the filter expression as variables. In the `info`\ncommand, the following context is set:\n\nWhen using `rabtap --info --mode=byExchange` (which is the default), the\nfollowing variables are bound:\n\n* the current exchange is bound to the variable [r.exchange](#exchange-type)\n* the current queue is bound to the variable [r.queue](#queue-type)\n* the current binding is bound to the variable [r.binding](#binding-type)\n\nWhen using `rabtap --info --mode=byConnection` , the following variables are bound:\n\n* the current connection is bound to the variable [r.connection](#connection-type)\n* the current channel is bound to the variable [r.connection](#channel-type)\n\nIn the `sub` and `tap` commands, the following context is set:\n\n* the current received message is bound to the variable [r.msg](#message-type),\n  which allows access to the message-metadata and the body\n* the current count of messages received that passed the filter is bound to\n `r.count`\n* Helper functions are provided to access the message body:\n  * the `r.toStr` function converts a byte buffer into a string, e.g. `let\n  b=toJSON(r.toStr(r.msg.Body))`\n  * the `r.gunzip` function decompresses the given byte buffer, e.g. `let\n  b=toJSON(r.toStr(r.gunzip(r.msg.Body)))`, allowing to inspect a compressed body\n  * the `r.body` function returns the message body, decompressing if necessary (i.e.\n    if `ContentType` is `gzip`), e.g.\n    `let b=toJSON(r.toStr(r.body(r.msg))`\n\n##### Examples\n\nThe examples assume that the `RABTAP_APIURI` environment variable points to the\nbroker to be used, e.g.  `http://guest:guest@localhost:15672/api`).\n\n* `rabtap info --filter \"exchange.Name == 'amq.direct'\" --omit-empty` - print\n  only queues bound to exchange `amq.direct` and skip all empty exchanges.\n* `rabtap info --filter \"queue.Name matches '.*test.*'\" --omit-empty` - print all\n  queues with `test` in their name\n* `rabtap info --filter \"queue.Name matches '.*test.*' \u0026\u0026 exchange.Type == 'topic'\" --omit-empty` - like\n  before, but consider only exchanges of type `topic`.\n* `rabtap info --filter \"queue.Consumers \u003e 0\" --omit --stats --consumers` - print\n  all queues with at least one consumer\n* `rabtap info --mode=byConnection --filter=\"r.channel.PrefetchCount \u003e 1` - list\n  all connection with channel that have a prefetch-count \u003e 1\n* `rabtap info --mode=byConnection --filter=\"r.connection.PeerCertSubject matches '.*CN=guest.*'\"` -\n  list all connection that were authenticated using mTLS and which certificates\n  subject contains `CN=guest`\n* `rabtap sub JDQ --filter=\"r.msg.RoutingKey == 'test'\"` - print only messages that\n  were sent with the routing key `test`\n* `rabtap sub JDQ --filter=\"let b=fromJSON(r.toStr(r.gunzip(r.msg.Body))); b.Name == 'JAN'\"` -\n  print only messages that have `.Name == \"JAN\"` in their gzipped payload,\n  interpreted as `JSON`\n\n#### Type reference\n\nThe types reflect more or less the JSON API objects of the [REST API of\nRabbitMQ](https://rawcdn.githack.com/rabbitmq/rabbitmq-management/v3.7.7/priv/www/api/index.html)\ntransformed to golang types.\n\n##### Exchange type\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefinition of the Exchange type\u003c/summary\u003e\n\n```go\ntype Exchange struct {\n    Name       string\n    Vhost      string\n    Type       string\n    Durable    bool\n    AutoDelete bool\n    Internal   bool\n    MessageStats struct {\n        PublishOut\n        PublishOutDetails struct {\n            Rate float64\n        }\n        PublishIn        int\n        PublishInDetails struct {\n            Rate float64\n        }\n    }\n}\n```\n\u003c/details\u003e\n\n##### Queue type\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefinition of the Queue type\u003c/summary\u003e\n\n```go\ntype Queue struct {\n    MessagesDetails struct {\n        Rate float64\n    }\n    Messages\n    MessagesUnacknowledgedDetails struct {\n        Rate float64\n    }\n    MessagesUnacknowledged int\n    MessagesReadyDetails   struct {\n        Rate float64\n    }\n    MessagesReady     int\n    ReductionsDetails struct {\n        Rate float64\n    }\n    Reductions int\n    Node       string\n    Exclusive            bool\n    AutoDelete           bool\n    Durable              bool\n    Vhost                string\n    Name                 string\n    MessageBytesPagedOut int\n    MessagesPagedOut     int\n    BackingQueueStatus   struct {\n        Mode string\n        Q1   int\n        Q2   int\n        Q3  int\n        Q4  int\n        Len int\n        NextSeqID         int\n        AvgIngressRate    float64\n        AvgEgressRate     float64\n        AvgAckIngressRate float64\n        AvgAckEgressRate  float64\n    }\n    MessageBytesPersistent     int\n    MessageBytesRAM            int\n    MessageBytesUnacknowledged int\n    MessageBytesReady          int\n    MessageBytes               int\n    MessagesPersistent         int\n    MessagesUnacknowledgedRAM  int\n    MessagesReadyRAM           int\n    MessagesRAM                int\n    GarbageCollection          struct {\n        MinorGcs        int\n        FullsweepAfter  int\n        MinHeapSize     int\n        MinBinVheapSize int\n        MaxHeapSize     int\n    }\n    State string\n    Consumers int\n    IdleSince string\n    Memory    int\n}\n```\n\u003c/details\u003e\n\n##### Binding type\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefinition of the Binding type\u003c/summary\u003e\n\n```go\ntype Binding struct {\n    Source          string\n    Vhost           string\n    Destination     string\n    DestinationType string\n    RoutingKey      string\n    PropertiesKey string\n}\n```\n\u003c/details\u003e\n\n##### Connection type\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefinition of the Connection type\u003c/summary\u003e\n\n```go\ntype Connection struct {\n    ReductionsDetails struct {\n        Rate float64\n    }\n    Reductions     int\n    RecvOctDetails struct {\n        Rate float64\n    }\n    RecvOct        int\n    SendOctDetails struct {\n        Rate float64\n    }\n    SendOct          int\n    ConnectedAt      int64\n    ClientProperties struct {\n        Product        string\n        Version        string\n        ConnectionName string\n        Capabilities   struct {\n            ConnectionBlocked    bool\n            ConsumerCancelNotify bool\n        }\n    }\n    ChannelMax        int\n    FrameMax          int\n    Timeout           int\n    Vhost             string\n    User              string\n    Protocol          string\n    SslHash           string\n    SslCipher         string\n    SslKeyExchange    string\n    SslProtocol       string\n    AuthMechanism     string\n    PeerCertValidity  string\n    PeerCertIssuer    string\n    PeerCertSubject   string\n    Ssl               bool\n    PeerHost          string\n    Host              string\n    PeerPort          int\n    Port              int\n    Name              string\n    Node              string\n    Type              string\n    GarbageCollection struct {\n        MinorGcs        int\n        FullsweepAfter  int\n        MinHeapSize     int\n        MinBinVheapSize int\n        MaxHeapSize     int\n    }\n    Channels int\n    State    string\n    SendPend int\n    SendCnt  int\n    RecvCnt  int\n}\n```\n\n\u003c/details\u003e\n\n##### Channel type\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefinition of the Channel type\u003c/summary\u003e\n\n```go\ntype Channel struct {\n    ReductionsDetails struct {\n        Rate float64\n    }\n    Reductions   int\n    MessageStats struct {\n        ReturnUnroutableDetails struct {\n            Rate float64\n        }\n        ReturnUnroutable int\n        ConfirmDetails   struct {\n            Rate float64\n        }\n        Confirm        int\n        PublishDetails struct {\n            Rate float64\n        }\n        Publish    int\n        Ack        int\n        AckDetails struct {\n            Rate float64\n        }\n        Deliver        int\n        DeliverDetails struct {\n            Rate float64\n        }\n        DeliverGet        int\n        DeliverGetDetails struct {\n            Rate float64\n        }\n        DeliverNoAck        int\n        DeliverNoAckDetails struct {\n            Rate float64\n        }\n        Get        int\n        GetDetails struct {\n            Rate float64\n        }\n        GetEmpty        int\n        GetEmptyDetails struct {\n            Rate float64\n        }\n        GetNoAck        int\n        GetNoAckDetails struct {\n            Rate float64\n        }\n        Redeliver        int\n        RedeliverDetails struct {\n            Rate float64\n        }\n    }\n    Vhost             string\n    User              string\n    Number            int\n    Name              string\n    Node              string\n    ConnectionDetails ConnectionDetails // see below\n    GarbageCollection struct {\n        MinorGcs        int\n        FullsweepAfter  int\n        MinHeapSize     int\n        MinBinVheapSize int\n        MaxHeapSize     int\n    }\n    State                  string\n    GlobalPrefetchCount    int\n    PrefetchCount          int\n    AcksUncommitted        int\n    MessagesUncommitted    int\n    MessagesUnconfirmed    int\n    MessagesUnacknowledged int\n    ConsumerCount          int\n    Confirm                bool\n    Transactional          bool\n    IdleSince              string\n}\n\ntype ConnectionDetails struct {\n    PeerHost string\n    PeerPort int\n    Name     string\n}\n```\n\n\u003c/details\u003e\n\n##### Message type\n\n\u003cdetails\u003e\n  \u003csummary\u003eDefinition of the Message type\u003c/summary\u003e\n\nThe currently received messages in the `sub` and `pub` commands is exposed to\nthe filter predicate under the name `r.msg`. The `Message` type is more or\nless the same as the `amqp.Delivery` type from the [golang amqp\npackage](https://github.com/rabbitmq/amqp091-go):\n\n```go\ntype Message struct {\n    Headers Table\n\n    // Properties\n    ContentType     string    // MIME content type\n    ContentEncoding string    // MIME content encoding\n    DeliveryMode    uint8     // queue implementation use - non-persistent (1) or persistent (2)\n    Priority        uint8     // queue implementation use - 0 to 9\n    CorrelationId   string    // application use - correlation identifier\n    ReplyTo         string    // application use - address to reply to (ex: RPC)\n    Expiration      string    // implementation use - message expiration spec\n    MessageId       string    // application use - message identifier\n    Timestamp       time.Time // application use - message timestamp\n    Type            string    // application use - message type name\n    UserId          string    // application use - creating user - should be authenticated user\n    AppId           string    // application use - creating application id\n\n    // Valid only with Channel.Consume\n    ConsumerTag string\n\n    // Valid only with Channel.Get\n    MessageCount uint32\n\n    DeliveryTag uint64\n    Redelivered bool\n    Exchange    string // basic.publish exchange\n    RoutingKey  string // basic.publish routing key\n\n    Body []byte\n}\n```\n\n\u003c/details\u003e\n\n## Build from source\n\n### Download and build using go install\n\n```text\n$ go install github.com/jandelgado/rabtap/cmd/rabtap@latest\n```\n\n### Build using Makefile and tests\n\nTo build rabtap from source, you need [go](https://golang.org/) (version \u003e= 1.18)\nand [golangci-lint](https://github.com/golangci/golangci-lint) installed.\n\n```text\n$ git clone https://github.com/jandelgado/rabtap \u0026\u0026 cd rabtap\n$ make test  -or- make short-test\n$ make\n```\n\nIn order to run all tests (`make test`) an instance of RabbitMQ is expected to\nrun on localhost. Easiest way to start one is running `make run-broker`, which\nwill start a RabbitMQ docker container (i.e.  `docker run -ti --rm -p 5672:5672\n-p 15672:15672 rabbitmq:3-management`). Another target, `short-tests`  runs\nonly unit-tests that down reach out to RabbitMQ.\n\n### Experimental WASM/wasip1 port\n\nRabtap can be compiled for Web Assembly (WASM) and the new `wasip1` `GOOS` and\nrun on the console using, e.g.\n[wasirun](https://github.com/stealthrocket/wasi-go). Example:\n\n```console\n$ go version\ngo version go1.21.3 linux/amd64\n$ make wasm-build\nCGO_ENABLED=1 GOOS=wasip1 GOARCH=wasm go build -o ./bin/rabtap-wasm ./cmd/rabtap\n$ wasirun --version\nwasirun v0.6.5\n$ wasirun  bin/rabtap-wasm -- --api \"http://guest:password@localhost:15672/api\" info --no-color\nhttp://localhost:15672/api (broker ver='3.12.6', mgmt ver='3.12.6', cluster='rabbit@3ea5bf2bac2f')\n└─ Vhost /\n   ├─ amq.direct (exchange(direct), [D])\n   ├─ amq.fanout (exchange(fanout), [D])\n   ├─ amq.headers (exchange(headers), [D])\n   ├─ amq.match (exchange(headers), [D])\n   ├─ amq.rabbitmq.trace (exchange(topic), [D|I])\n   └─ amq.topic (exchange(topic), [D])\n```\n\nAnother example using `wasirun` and `wasmedge` to publish and subscribe\nto a queue:\n\n```console\n$ URI=\"amqp://guest:password@localhost/\"\n$ rabtap queue create test\n$ rabtap queue bind test to amq.topic --bindingkey=key\n$ echo \"hello\" | wasmedge  bin/rabtap-wasm  --uri \"$URI\" pub --exchange amq.topic --routingkey=key\n$ wasirun  bin/rabtap-wasm -- --uri \"$URI\" sub test --limit=1\n------ message received on 2023-10-29T11:48:56Z ------\nexchange.......: amq.topic\nroutingkey.....: key\nhello\n```\n\nSee [my blog](https://jandelgado.github.io/blog/posts/rabtap-wasm) for details.\n\nLimitations:\n\n* environment variables like `RABTAP_AMQPURI` not supported, must specify\n  all options on the command line\n* depending on the runtime, colors must explicitly set or disabled using\n  `--color` and `--no-color`, since terminal detection not working.\n\n## Test data generator\n\nA simple [test data generator tool](cmd/testgen/README.md) for manual tests is\nincluded in the `cmd/testgen` directory.\n\n## Contributing\n\n* fork this repository\n* create your feature branch\n* add code\n* add tests and make sure test coverage does not fall (`make test`)\n* add [documentation](README.md)\n* commit changes\n* submit a PR\n\n## Author\n\nJan Delgado (jdelgado at gmx dot net)\n\n## Copyright and license\n\nCopyright (c) 2017-2024 Jan Delgado.\nrabtap is licensed under the GPLv3 license.","funding_links":[],"categories":["Event BUS","Messaging","消息系统","Relational Databases","消息","消息传递","机器学习"],"sub_categories":["RabbitMQ","Advanced Console UIs","SQL 查询语句构建库","Search and Analytic Databases","检索及分析资料库","交流"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjandelgado%2Frabtap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjandelgado%2Frabtap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjandelgado%2Frabtap/lists"}