Skip to content

Commit

Permalink
Update for MQ 9.4.1
Browse files Browse the repository at this point in the history
  • Loading branch information
ibmmqmet committed Oct 25, 2024
1 parent e93fd39 commit 53f6efe
Show file tree
Hide file tree
Showing 85 changed files with 1,771 additions and 457 deletions.
17 changes: 12 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
# Changelog
Newest updates are at the top of this file.

### Oct 24 2024 (v5.6.1)
* Update to MQ 9.4.1
* Some linter-suggested code changes
* Add PasswordFile configuration option for MQ authentication
* Add note about TZ configuration (#314)
* Add an example dashboard for the OTel exporter to show any Traces sent to Jaeger

### Jun 18 2024 (v5.6.0)
* Update to MQ 9.4.0
* Update all vendored dependencies
* Add OTLP/http option to OTel emitter
* Remove "EXPERIMENTAL" flag
* Convert OTEL and Prometheus sample dashboards to newer Grafana panels
* Update to Go 1.21 as baseline (OTEL requirement)
* Permit connection to unnamed (default) queue manager
* Permit connection to unnamed (default) queue manager

### Mar 21 2024 (v5.5.4.1)
* Update main Dockerfile to use different base build image
* Update main Dockerfile to use different base build image
because of glibc issues when copying into regular MQ container

### Feb 29 2024 (v5.5.4)
Expand Down Expand Up @@ -44,7 +51,7 @@ Newest updates are at the top of this file.

### Jan 10 2023 (v5.3.3)
* Copy in metrics.txt summary of available metrics from mq-golang
* JSON exporter - consistent objecttype for qmgr, merge published and
* JSON exporter - consistent objecttype for qmgr, merge published and
polled metrics (#188)
* JSON exporter - allow configuration (`recordmax`) for number of objects
printed in a single JSON record (also #188)
Expand All @@ -58,10 +65,10 @@ Newest updates are at the top of this file.
* Add sample script showing TLS configuration in container
* Update Prometheus channel status sample dashboard to show channel instance counts
* Add AMQP channel status reporting to all collectors
* Add single CLUSTER tag to queues (ibm-messaging/mq-golang#191)
* Add single CLUSTER tag to queues (ibm-messaging/mq-golang#191)

### Jul 07 2022 (v5.3.1)
* Update to use v5.3.1 of mq-golang repository
* Update to use v5.3.1 of mq-golang repository

### Jun 23 2022 (v5.3.0)
* Update to MQ 9.3.0
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ ARG EXPORTER
ENV EXPORTER=${EXPORTER} \
ORG="github.com/ibm-messaging" \
REPO="mq-metric-samples" \
VRMF=9.4.0.0 \
VRMF=9.4.1.0 \
CGO_CFLAGS="-I/opt/mqm/inc/" \
CGO_LDFLAGS_ALLOW="-Wl,-rpath.*" \
genmqpkg_incnls=1 \
Expand Down
7 changes: 4 additions & 3 deletions Dockerfile.build
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ RUN mkdir -p $GOPATH/src $GOPATH/bin $GOPATH/pkg \
# Location of the downloadable MQ client package \
ENV RDURL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqdev/redist" \
RDTAR="IBM-MQC-Redist-Linux${MQARCH}.tar.gz" \
VRMF=9.4.0.0
VRMF=9.4.1.0

# Install the MQ client from the Redistributable package. This also contains the
# header files we need to compile against. Setup the subset of the package
Expand All @@ -78,6 +78,7 @@ RUN cd /opt/mqm \
# Insert the script that will do the build
COPY --chmod=777 scripts/buildInDocker.sh $GOPATH

ENV REPO="mq-metric-samples"
WORKDIR $GOPATH/src/$ORG/$REPO
COPY --chmod=777 go.mod .
COPY --chmod=777 go.sum .
Expand All @@ -87,8 +88,8 @@ COPY --chmod=777 config.common.yaml .

# Copy the rest of the source tree from this directory into the container and
# make sure it's readable by the user running the container
ENV REPO="mq-metric-samples"
COPY --chmod=777 . $GOPATH/src/$ORG/$REPO

# Set the entrypoint to the script that will do the compilation
ENTRYPOINT $GOPATH/buildInDocker.sh
WORKDIR $GOPATH
ENTRYPOINT [ "./buildInDocker.sh" ]
5 changes: 3 additions & 2 deletions Dockerfile.run
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ RUN apt-get update \
# Location of the downloadable MQ client package \
ENV RDURL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqdev/redist" \
RDTAR="IBM-MQC-Redist-Linux${MQARCH}.tar.gz" \
VRMF=9.4.0.0
VRMF=9.4.1.0

# Install the MQ client from the Redistributable package. This also contains the
# header files we need to compile against. Setup the subset of the package
Expand Down Expand Up @@ -70,4 +70,5 @@ ENV IBMMQ_GLOBAL_CONFIGURATIONFILE=/opt/config/$MONITOR.yaml
# ENV IBMMQ_CONNECTION_QUEUEMANAGER=QM1

# The configuration file should be mounted from the host into the /opt/config directory.
CMD /opt/bin/$MONITOR
RUN ln /opt/bin/$MONITOR /opt/bin/mqmonitor
CMD [ "/opt/bin/mqmonitor" ]
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ required to point at non-default directories for the MQ C SDK.
### Building a component on your system directly

* You need to have the MQ client libraries installed first.
* Create a directory where you want to work with the programs.
* Create a directory where you want to work with the programs.
* Change to that directory.
* Use git to get a copy of this repository into a new directory in the workspace. For example:

Expand Down Expand Up @@ -82,7 +82,7 @@ You still need to provide the configuration file at runtime, perhaps as a mounte
```
docker build -t mqprom:1.0 .
docker run -p 9157:9157 -v <directory>/mq_prometheus.yaml:/opt/config/mq_prometheus.yaml mqprom:1.0
```
```

### Platform support
This Dockerfile should work for a variety of platforms. For those with a Redistributable client, it uses `curl` to
Expand Down Expand Up @@ -260,8 +260,26 @@ The userid is configured using the `-ibmmq.userid` flag. The password can be set
flag, or by passing it via stdin. That allows it to be piped from an external stash file or some other mechanism. Using
the command line flags for controlling passwords is not recommended for security-sensitive environments.

You can also use the `-ibmmq.passwordFile` where the file contains a plaintext password. This might be appropriate for
container environments where secrets are mounted into the running container.

Where authentication is needed for access to a database, passwords for those can also be passed via stdin.

### Timezones
For some configurations, especially when running the exporters as client-connected rather than directly alongside
the queue manager, you may see warnings about timezone offsets. Perhaps the exporter is in a different timezone
than the queue manager. One particular warning would be: "Status reports appear to be from the future".

The `tzOffset` configuration attribute may help to deal with this - it indicates the difference between the queue manager
timezone and the exporter's.

When running components in a container, you may also wish to adjust the container's timezone for consistency. This may
need you to set the `TZ` environment variable for the container. You may also need to set timezone data files for the
container as many standard container base images do not do that. See
[here](https://access.redhat.com/solutions/2567961) for some ways to do that. The `Workaround 3` has been
[reported](https://github.com/ibm-messaging/mq-metric-samples/issues/314) as being effective.


## YAML configuration for all exporters
Instead of providing all of the configuration for the exporters via command-line flags, you can also provide the
configuration in a YAML file. Then only the `-f` command-line option is required for the exporter to point at the file.
Expand Down
17 changes: 14 additions & 3 deletions TUNING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ monitoring those queues. Some default configuration options might need tuning to
the frequency of generation and/or collection may be appropriate. There are several places where tuning might be
done: in this collector, in the database configuration, and in the queue manager.

The following sections describe different pieces that you might want to look at.
The following sections describe different pieces that you might want to look at.

The document is mostly written from the viewpoint of using Prometheus as the database. That is mainly because
Prometheus has the unique "pull" model, where the server calls the collector at configured intervals. Other databases and
Expand All @@ -20,13 +20,13 @@ If you cannot avoid running as a client (for example, you are trying to monitor
network latency between the queue manager and collector as low as possible. For z/OS, you might consider running the
collector in a zLinux LPAR on the same machine. Or perhaps in a zCX container.

If you are running as a client, then configure it to take advantage of readahead when getting publications. This is done by
If you are running as a client, then configure it to take advantage of readahead when getting publications. This is done by
setting `DEFREADA(YES)` on the nominated ReplyQueue(s).

## Collection processing time
The collector reports on how long it takes to collect and process the data on each interval. You can see this in a debug
log. The Prometheus collector also has a `ibmmq_qmgr_exporter_collection_time` metric. Note that this time is the value
as seen by the main collection thread; the real total time as seen by Prometheus is usually longer. This is because there
as seen by the main collection thread; the real total time as seen by Prometheus is usually longer. This is because there
is likely still work going on in the background to send metrics to the database, and for it to be successfully ingested.

The first time that the collection time exceeds the Prometheus default `scrape_timeout` value, a warning message is
Expand Down Expand Up @@ -119,3 +119,14 @@ time. The default wait of 3 seconds can be tuned using the `connection.waitInter
For all collectors _except_ Prometheus, a small number of these timeout errors are permitted consecutively. The failure
count is reset after a successful collection. See _pkg/errors/errors.go_ for details. The Prometheus collector has an
automatic reconnect option after failures, so does not currently use this strategy.

## Prometheus configuration
There are some options that can be applied in the Prometheus configuration for reducing the number of metrics stored.
These do not affect the collection from the queue manager, but Prometheus can apply filters during the collection phase
so that only a subset is actually written to the database. This can be particularly relevant if you are then sending the
data onwards to something like Grafana Cloud. The `metric_relabel_configs` section of Prometheus configuration seems to
be the key area.

See
[here](https://grafana.com/docs/grafana-cloud/cost-management-and-billing/reduce-costs/metrics-costs/client-side-filtering/)
and [here](https://www.robustperception.io/dropping-metrics-at-scrape-time-with-prometheus/) for more details.
6 changes: 5 additions & 1 deletion cmd/mq_aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ func initConfig() error {
// Process password for MQ connection
if err == nil {
if config.cf.CC.UserId != "" && config.cf.CC.Password == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
if config.cf.PasswordFile == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
} else {
config.cf.CC.Password, err = cf.GetPasswordFromFile(config.cf.PasswordFile, false)
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/mq_aws/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,10 @@ func Collect() error {
if config.cf.RediscoverDuration > 0 {
if elapsed >= config.cf.RediscoverDuration {
log.Debugf("Doing queue rediscovery")
err = mqmetric.RediscoverAndSubscribe(discoverConfig)
_ = mqmetric.RediscoverAndSubscribe(discoverConfig)
lastQueueDiscovery = thisDiscovery
//if err == nil {
err = mqmetric.RediscoverAttributes(ibmmq.MQOT_CHANNEL, config.cf.MonitoredChannels)
_ = mqmetric.RediscoverAttributes(ibmmq.MQOT_CHANNEL, config.cf.MonitoredChannels)
err = mqmetric.RediscoverAttributes(mqmetric.OT_CHANNEL_AMQP, config.cf.MonitoredAMQPChannels)

//}
Expand Down
9 changes: 7 additions & 2 deletions cmd/mq_coll/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ package main
*/

import (
cf "github.com/ibm-messaging/mq-metric-samples/v5/pkg/config"
"os"

cf "github.com/ibm-messaging/mq-metric-samples/v5/pkg/config"
)

type mqTTYConfig struct {
Expand Down Expand Up @@ -80,7 +81,11 @@ func initConfig() error {

if err == nil {
if config.cf.CC.UserId != "" && config.cf.CC.Password == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
if config.cf.PasswordFile == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
} else {
config.cf.CC.Password, err = cf.GetPasswordFromFile(config.cf.PasswordFile, false)
}
}
}

Expand Down
12 changes: 3 additions & 9 deletions cmd/mq_coll/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import (

var (
first = true
errorCount = 0
lastPoll = time.Now()
lastQueueDiscovery time.Time
platformString = ""
Expand Down Expand Up @@ -92,7 +91,7 @@ func Collect() error {
pollError := err
if pollStatus {
if config.cf.CC.UseStatus {
err := mqmetric.CollectQueueManagerStatus()
err = mqmetric.CollectQueueManagerStatus()
if err != nil {
log.Errorf("Error collecting queue manager status: %v", err)
pollError = err
Expand Down Expand Up @@ -164,9 +163,9 @@ func Collect() error {
elapsed = thisDiscovery.Sub(lastQueueDiscovery)
if config.cf.RediscoverDuration > 0 {
if elapsed >= config.cf.RediscoverDuration {
err = mqmetric.RediscoverAndSubscribe(discoverConfig)
_ = mqmetric.RediscoverAndSubscribe(discoverConfig)
lastQueueDiscovery = thisDiscovery
err = mqmetric.RediscoverAttributes(ibmmq.MQOT_CHANNEL, config.cf.MonitoredChannels)
_ = mqmetric.RediscoverAttributes(ibmmq.MQOT_CHANNEL, config.cf.MonitoredChannels)
err = mqmetric.RediscoverAttributes(mqmetric.OT_CHANNEL_AMQP, config.cf.MonitoredAMQPChannels)

}
Expand Down Expand Up @@ -501,11 +500,6 @@ func printPoint(series string, metric string, val float32, tags map[string]strin
return
}

func fixup(s1 string) string {
s2 := strings.Replace(s1, ".", "_", -1)
return s2
}

// Only the following characters are allowed in names: a to z, A to Z, 0 to 9, -, _, .,
func sanitiseString(s string) string {
r := make([]rune, len(s))
Expand Down
6 changes: 5 additions & 1 deletion cmd/mq_influx/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ func initConfig() error {
// Process password for MQ connection
if err == nil {
if config.cf.CC.UserId != "" && config.cf.CC.Password == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
if config.cf.PasswordFile == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
} else {
config.cf.CC.Password, err = cf.GetPasswordFromFile(config.cf.PasswordFile, false)
}
}
}

Expand Down
12 changes: 6 additions & 6 deletions cmd/mq_influx/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ import (
)

var (
first = true
totalErrorCount = int64(0)
loopErrorCount = int64(0)
errorSync = make(chan bool)
first = true
totalErrorCount = int64(0)
loopErrorCount = int64(0)
// errorSync = make(chan bool)
platformString = ""
lastPoll = time.Now()
lastQueueDiscovery time.Time
Expand Down Expand Up @@ -177,9 +177,9 @@ func Collect(c client.Client) error {
if config.cf.RediscoverDuration > 0 {
if elapsed >= config.cf.RediscoverDuration {
log.Debugf("Doing queue rediscovery")
err = mqmetric.RediscoverAndSubscribe(discoverConfig)
_ = mqmetric.RediscoverAndSubscribe(discoverConfig)
lastQueueDiscovery = thisDiscovery
err = mqmetric.RediscoverAttributes(ibmmq.MQOT_CHANNEL, config.cf.MonitoredChannels)
_ = mqmetric.RediscoverAttributes(ibmmq.MQOT_CHANNEL, config.cf.MonitoredChannels)
err = mqmetric.RediscoverAttributes(mqmetric.OT_CHANNEL_AMQP, config.cf.MonitoredAMQPChannels)

}
Expand Down
6 changes: 5 additions & 1 deletion cmd/mq_json/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ func initConfig() error {

if err == nil {
if config.cf.CC.UserId != "" && config.cf.CC.Password == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
if config.cf.PasswordFile == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
} else {
config.cf.CC.Password, err = cf.GetPasswordFromFile(config.cf.PasswordFile, false)
}
}
}

Expand Down
12 changes: 4 additions & 8 deletions cmd/mq_json/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,14 @@ import (
)

var (
first = true
errorCount = 0
first = true
// errorCount = 0
lastPoll = time.Now()
lastQueueDiscovery = time.Now()
platformString = ""
fixupString = make(map[string]string)
)

const (
blankString = " "
)

type collectionTimeStruct struct {
TimeStamp string `json:"timeStamp"`
Epoch int64 `json:"epoch"`
Expand Down Expand Up @@ -189,9 +185,9 @@ func Collect() error {
elapsed = thisDiscovery.Sub(lastQueueDiscovery)
if config.cf.RediscoverDuration > 0 {
if elapsed >= config.cf.RediscoverDuration {
err = mqmetric.RediscoverAndSubscribe(discoverConfig)
_ = mqmetric.RediscoverAndSubscribe(discoverConfig)
lastQueueDiscovery = thisDiscovery
err = mqmetric.RediscoverAttributes(ibmmq.MQOT_CHANNEL, config.cf.MonitoredChannels)
_ = mqmetric.RediscoverAttributes(ibmmq.MQOT_CHANNEL, config.cf.MonitoredChannels)
err = mqmetric.RediscoverAttributes(mqmetric.OT_CHANNEL_AMQP, config.cf.MonitoredAMQPChannels)
}
}
Expand Down
6 changes: 5 additions & 1 deletion cmd/mq_opentsdb/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@ func initConfig() error {
// Process password for MQ connection
if err == nil {
if config.cf.CC.UserId != "" && config.cf.CC.Password == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
if config.cf.PasswordFile == "" {
config.cf.CC.Password = cf.GetPasswordFromStdin("Enter password for MQ: ")
} else {
config.cf.CC.Password, err = cf.GetPasswordFromFile(config.cf.PasswordFile, false)
}
}
}

Expand Down
Loading

0 comments on commit 53f6efe

Please sign in to comment.