diff --git a/.gitignore b/.gitignore index 80f37da..2b65fa8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ dist/ *.key oci8.pc *.skip -.vscode \ No newline at end of file +.vscode +**/target/ \ No newline at end of file diff --git a/README.md b/README.md index 2c4ae82..287d9c1 100644 --- a/README.md +++ b/README.md @@ -746,7 +746,7 @@ The exporter includes a set of metrics for monitoring TxEventQ and a pre-built G > Note: The metrics are written for Oracle Database 21c or later. -### How to create a topic +### How to create some traffic with PL/SQL If you need to create a topic to monitor, you can use these statements to create and start a topic, and create a subscriber: @@ -807,6 +807,19 @@ begin end; ``` +### How to create some traffic with Java (Spring Boot) + +A simple load generator is provided in [this directory](./docker-compose/txeventq-load/) which you can use to create some traffic so you can experiment with the sample dashboard. + +To run the sample, first update [application.yaml](./docker-compose/txeventq-load/src/main/resources/application.yaml) with the correct IP address for your database, then start the application as follows: + +```bash +mvn spring-boot:run +``` + +The application will create ten queues names TOPIC_0 through TOPIC_9 and randomly produce and consume messages on those queues. The example dashboard shown below was monitoring traffic produced using this application. + + ### Metrics definitions The metrics definitions are provided in [this file](./custom-metrics-example/txeventq-metrics.toml). You need to provide this file to the exporter, e.g., by adding it to your container image, or creating a Kubernetes config map containing the file and mounting that config map as a volume in your deployment. You also need to set the `CUSTOM_METRICS` environment variable to the location of this file. @@ -835,7 +848,7 @@ A Grafana dashboard for Transactional Event Queues is provided [in this file](./ The dashboard will look like this: -![](./doc/txeventq-dashboard.png) +![](./doc/txeventq-dashboard-v2.png) ## Developer notes diff --git a/doc/txeventq-dashboard-v2.png b/doc/txeventq-dashboard-v2.png new file mode 100755 index 0000000..9418bf2 Binary files /dev/null and b/doc/txeventq-dashboard-v2.png differ diff --git a/docker-compose/compose.yaml b/docker-compose/compose.yaml index 2672689..18c47a4 100644 --- a/docker-compose/compose.yaml +++ b/docker-compose/compose.yaml @@ -48,9 +48,9 @@ services: ports: - 9161:9161 environment: - - DB_USERNAME=system + - DB_USERNAME=pdbadmin - DB_PASSWORD=Welcome12345 - - DB_CONNECT_STRING=free23c:1521/free + - DB_CONNECT_STRING=free23c:1521/freepdb1 - CUSTOM_METRICS=/exporter/txeventq-metrics.toml volumes: - ./exporter:/exporter diff --git a/docker-compose/grafana/dashboards/txeventq.json b/docker-compose/grafana/dashboards/txeventq.json index 7007171..6f33932 100755 --- a/docker-compose/grafana/dashboards/txeventq.json +++ b/docker-compose/grafana/dashboards/txeventq.json @@ -1,14 +1,4 @@ { - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], "annotations": { "list": [ { @@ -34,43 +24,10 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 28, - "iteration": 1655322497532, + "id": 2, "links": [], "liveNow": false, "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "Prometheus" - }, - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 96, - "options": { - "alertInstanceLabelFilter": "", - "alertName": "", - "dashboardAlerts": false, - "groupBy": [], - "groupMode": "default", - "maxItems": 20, - "sortOrder": 1, - "stateFilter": { - "error": true, - "firing": true, - "inactive": false, - "noData": false, - "normal": false, - "pending": true - } - }, - "title": "Alerts", - "type": "alertlist" - }, { "collapsed": false, "datasource": { @@ -81,7 +38,7 @@ "h": 1, "w": 24, "x": 0, - "y": 8 + "y": 0 }, "id": 64, "panels": [], @@ -139,10 +96,10 @@ "overrides": [] }, "gridPos": { - "h": 5, + "h": 4, "w": 4, "x": 0, - "y": 9 + "y": 1 }, "id": 48, "links": [], @@ -161,7 +118,7 @@ }, "textMode": "auto" }, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "targets": [ { "expr": "oracledb_teq_total_queues{inst_id=~\"[[instance]]\"}", @@ -190,10 +147,10 @@ "fill": 3, "fillGradient": 4, "gridPos": { - "h": 13, - "w": 12, + "h": 12, + "w": 16, "x": 4, - "y": 9 + "y": 1 }, "hiddenSeries": false, "id": 56, @@ -213,7 +170,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -317,10 +274,10 @@ "overrides": [] }, "gridPos": { - "h": 5, + "h": 6, "w": 4, - "x": 16, - "y": 9 + "x": 20, + "y": 1 }, "id": 12, "links": [], @@ -339,7 +296,7 @@ }, "textMode": "auto" }, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "targets": [ { "expr": "sum(oracledb_teq_enqueued_msgs{inst_id=~\"[[instance]]\"})", @@ -354,24 +311,13 @@ "type": "prometheus", "uid": "Prometheus" }, - "description": "Total dequeued messages for the entire queue system", + "description": "The number of TxEventQs running", "fieldConfig": { "defaults": { "color": { - "fixedColor": "rgb(196, 22, 25)", - "mode": "fixed" + "mode": "thresholds" }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], + "mappings": [], "thresholds": { "mode": "absolute", "steps": [ @@ -385,22 +331,22 @@ } ] }, - "unit": "short" + "unit": "none" }, "overrides": [] }, "gridPos": { - "h": 5, + "h": 4, "w": 4, - "x": 20, - "y": 9 + "x": 0, + "y": 5 }, - "id": 49, + "id": 30, "links": [], "maxDataPoints": 100, "options": { - "colorMode": "none", - "graphMode": "area", + "colorMode": "value", + "graphMode": "none", "justifyMode": "auto", "orientation": "horizontal", "reduceOptions": { @@ -412,14 +358,14 @@ }, "textMode": "auto" }, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "targets": [ { - "expr": "sum(oracledb_teq_dequeued_msgs{inst_id=~\"[[instance]]\"})", + "expr": "oracledb_teq_total_queues{inst_id=~\"[[instance]]\"}", "refId": "A" } ], - "title": "Overall Dequeue Messages", + "title": "Total TxEventQ", "type": "stat" }, { @@ -427,13 +373,24 @@ "type": "prometheus", "uid": "Prometheus" }, - "description": "The number of TxEventQs running", + "description": "Total dequeued messages for the entire queue system", "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "rgb(196, 22, 25)", + "mode": "fixed" }, - "mappings": [], + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], "thresholds": { "mode": "absolute", "steps": [ @@ -447,22 +404,22 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "gridPos": { - "h": 4, + "h": 6, "w": 4, - "x": 0, - "y": 14 + "x": 20, + "y": 7 }, - "id": 30, + "id": 49, "links": [], "maxDataPoints": 100, "options": { - "colorMode": "value", - "graphMode": "none", + "colorMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "horizontal", "reduceOptions": { @@ -474,121 +431,16 @@ }, "textMode": "auto" }, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "targets": [ { - "expr": "oracledb_teq_total_queues{inst_id=~\"[[instance]]\"}", + "expr": "sum(oracledb_teq_dequeued_msgs{inst_id=~\"[[instance]]\"})", "refId": "A" } ], - "title": "Total TxEventQ", + "title": "Overall Dequeue Messages", "type": "stat" }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": { - "type": "prometheus", - "uid": "Prometheus" - }, - "description": "Approximate aggregate bytes-in/bytes-out rates for all TxEventQs", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 8, - "w": 8, - "x": 16, - "y": 14 - }, - "hiddenSeries": false, - "id": 87, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "8.5.3", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "Total Bytes In Rate", - "yaxis": 1 - }, - { - "alias": "Total Bytes Out Rate", - "yaxis": 2 - } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(oracledb_system_network_received_from_client{inst_id=~\"[[instance]]\"}[3m])", - "interval": "", - "legendFormat": "Total Bytes In Rate", - "refId": "A" - }, - { - "expr": "rate(oracledb_system_network_sent_to_client{inst_id=~\"[[instance]]\"}[3m])", - "interval": "", - "legendFormat": "Total Bytes Out Rate", - "refId": "B" - } - ], - "thresholds": [], - "timeRegions": [], - "title": "Overall Bytes In/Bytes Out Rate", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "mode": "time", - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": "Total Bytes In Rate (Bytes/Second)", - "logBase": 1, - "show": true - }, - { - "format": "decbytes", - "label": "Total Bytes Out Rate (Bytes/Second)", - "logBase": 1, - "show": true - } - ], - "yaxis": { - "align": false - } - }, { "datasource": { "type": "prometheus", @@ -622,7 +474,7 @@ "h": 4, "w": 4, "x": 0, - "y": 18 + "y": 9 }, "id": 50, "links": [], @@ -641,7 +493,7 @@ }, "textMode": "auto" }, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "targets": [ { "expr": "oracledb_teq_total_subscribers{inst_id=~\"[[instance]]\"}", @@ -652,299 +504,235 @@ "type": "stat" }, { - "columns": [ - { - "$$hashKey": "object:262", - "text": "Current", - "value": "current" - } - ], "datasource": { - "type": "prometheus", - "uid": "Prometheus" + "type": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Message Latency" + }, + "properties": [ + { + "id": "unit", + "value": "ms" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dequeue Rate / Enqueue Rate" + }, + "properties": [ + { + "id": "unit", + "value": "percentunit" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Enqueued Messages" + }, + "properties": [ + { + "id": "unit", + "value": "short" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Dequeued Messages" + }, + "properties": [ + { + "id": "unit", + "value": "short" + } + ] + } + ] }, - "description": "TxEventQ Quick Lookup Table: simply click on the metric name and order it increasingly or decreasingly, easy to identify a 'good' queue or a 'bad' queue.", - "fontSize": "150%", "gridPos": { - "h": 8, + "h": 12, "w": 24, "x": 0, - "y": 22 - }, - "id": 93, - "pageSize": 5, - "showHeader": true, - "sort": { - "desc": false + "y": 13 }, - "styles": [ - { - "$$hashKey": "object:558", - "alias": "Queue Depth", - "align": "auto", - "colorMode": "value", - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 0, - "pattern": "Value #A", - "thresholds": [ - "" - ], - "type": "number", - "unit": "short" - }, - { - "$$hashKey": "object:559", - "alias": "Message Latency", - "align": "auto", - "colorMode": "value", - "colors": [ - "#5794F2", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 0, - "mappingType": 1, - "pattern": "Value #D", - "thresholds": [], - "type": "number", - "unit": "ms" - }, - { - "$$hashKey": "object:560", - "alias": "", - "align": "auto", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "Time", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "$$hashKey": "object:561", - "alias": "Enqueue Rate", - "align": "auto", - "colorMode": "value", - "colors": [ - "#73BF69", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "Value #B", - "thresholds": [], - "type": "number", - "unit": "short" - }, - { - "$$hashKey": "object:562", - "alias": "Dequeue Rate", - "align": "auto", - "colorMode": "value", - "colors": [ - "#FF9830", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "Value #C", - "thresholds": [], - "type": "number", - "unit": "short" - }, - { - "$$hashKey": "object:563", - "alias": "Enqueue Message", - "align": "auto", - "colorMode": "value", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 3, - "mappingType": 1, - "pattern": "Value #E", - "thresholds": [], - "type": "number", - "unit": "short" - }, - { - "$$hashKey": "object:564", - "alias": "Dequeue Message", - "align": "auto", - "colorMode": "value", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 3, - "mappingType": 1, - "pattern": "Value #F", - "thresholds": [], - "type": "number", - "unit": "short" - }, - { - "$$hashKey": "object:637", - "alias": "Deq Rate / Enq Rate", - "align": "auto", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" + "id": 94, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 3, - "mappingType": 1, - "pattern": "Value #G", - "thresholds": [], - "type": "number", - "unit": "short" + "show": false }, - { - "$$hashKey": "object:6725", - "alias": "Enq-Deq", - "align": "auto", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "Value #H", - "thresholds": [], - "type": "number", - "unit": "short" - } - ], + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "10.1.1", "targets": [ { "datasource": { - "type": "prometheus", - "uid": "Prometheus" + "type": "prometheus" }, + "editorMode": "code", "exemplar": false, "expr": "sum(oracledb_teq_remained_msgs) by (queue_name)", "format": "table", "instant": true, - "interval": "", "legendFormat": "{{queue_name}}", + "range": false, "refId": "A" }, { "datasource": { - "type": "prometheus", - "uid": "Prometheus" + "type": "prometheus" }, + "editorMode": "code", "exemplar": false, "expr": "sum(oracledb_teq_message_latency_1) by (queue_name)", "format": "table", + "hide": false, "instant": true, - "interval": "", "legendFormat": "{{queue_name}}", - "refId": "D" + "range": false, + "refId": "B" }, { "datasource": { - "type": "prometheus", - "uid": "Prometheus" + "type": "prometheus" }, + "editorMode": "code", "exemplar": false, "expr": "sum(rate(oracledb_teq_enqueued_msgs[3m])) by (queue_name)", "format": "table", + "hide": false, "instant": true, - "interval": "", "legendFormat": "{{queue_name}}", - "refId": "B" + "range": false, + "refId": "C" }, { "datasource": { - "type": "prometheus", - "uid": "Prometheus" + "type": "prometheus" }, + "editorMode": "code", "exemplar": false, "expr": "sum(rate(oracledb_teq_dequeued_msgs[3m])) by (queue_name)", "format": "table", + "hide": false, "instant": true, - "interval": "", "legendFormat": "{{queue_name}}", - "refId": "C" + "range": false, + "refId": "D" }, { "datasource": { - "type": "prometheus", - "uid": "Prometheus" + "type": "prometheus" }, + "editorMode": "code", "exemplar": false, "expr": "sum(oracledb_teq_enqueued_msgs) by (queue_name)", "format": "table", + "hide": false, "instant": true, - "interval": "", - "legendFormat": "", + "legendFormat": "{{queue_name}}", + "range": false, "refId": "E" }, { "datasource": { - "type": "prometheus", - "uid": "Prometheus" + "type": "prometheus" }, + "editorMode": "code", "exemplar": false, "expr": "sum(oracledb_teq_dequeued_msgs) by (queue_name)", "format": "table", + "hide": false, "instant": true, - "interval": "", - "legendFormat": "", + "legendFormat": "{{queue_name}}", + "range": false, "refId": "F" }, { "datasource": { - "type": "prometheus", - "uid": "Prometheus" + "type": "prometheus" }, + "editorMode": "code", "exemplar": false, "expr": "sum(rate(oracledb_teq_dequeued_msgs[3m])) by (queue_name) / sum(rate(oracledb_teq_enqueued_msgs[3m])) by (queue_name) ", "format": "table", "hide": false, "instant": true, - "interval": "", "legendFormat": "{{queue_name}}", + "range": false, "refId": "G" + } + ], + "title": "TxEventQ Overall Metrics", + "transformations": [ + { + "id": "merge", + "options": {} }, { - "datasource": { - "type": "prometheus", - "uid": "Prometheus" - }, - "exemplar": false, - "expr": "sum(oracledb_teq_enqueued_msgs) by (queue_name) - sum(oracledb_teq_dequeued_msgs) by (queue_name)", - "format": "table", - "hide": false, - "instant": true, - "interval": "", - "legendFormat": "{{queue_name}}", - "refId": "H" + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": {}, + "renameByName": { + "Value #A": "Queue Depth", + "Value #B": "Message Latency", + "Value #C": "Enqueue Rate", + "Value #D": "Dequeue Rate", + "Value #E": "Enqueued Messages", + "Value #F": "Dequeued Messages", + "Value #G": "Dequeue Rate / Enqueue Rate", + "queue_name": "Queue Name" + } + } } ], - "title": "TxEventQ Quick Lookup Table ", - "transform": "table", - "type": "table-old" + "type": "table" }, { "collapsed": false, @@ -956,7 +744,7 @@ "h": 1, "w": 24, "x": 0, - "y": 30 + "y": 25 }, "id": 34, "panels": [], @@ -985,7 +773,7 @@ "h": 9, "w": 9, "x": 0, - "y": 31 + "y": 26 }, "hiddenSeries": false, "id": 36, @@ -1005,7 +793,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -1090,7 +878,7 @@ "h": 9, "w": 9, "x": 9, - "y": 31 + "y": 26 }, "hiddenSeries": false, "id": 38, @@ -1110,7 +898,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -1183,14 +971,19 @@ "h": 2, "w": 6, "x": 18, - "y": 31 + "y": 26 }, "id": 45, "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, "content": "
$queue
", "mode": "html" }, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "title": "TxEventQ Name", "type": "text" }, @@ -1204,14 +997,19 @@ "h": 2, "w": 6, "x": 18, - "y": 33 + "y": 28 }, "id": 46, "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, "content": "
$subscriber
", "mode": "html" }, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "title": "Subscriber Name", "type": "text" }, @@ -1237,7 +1035,7 @@ "h": 6, "w": 6, "x": 18, - "y": 35 + "y": 30 }, "hiddenSeries": false, "id": 83, @@ -1257,7 +1055,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "8.5.3", + "pluginVersion": "10.1.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -1307,7 +1105,7 @@ } ], "refresh": "5s", - "schemaVersion": 36, + "schemaVersion": 38, "style": "dark", "tags": [], "templating": { @@ -1316,8 +1114,8 @@ "allValue": "1 | 2 | 3", "current": { "selected": false, - "text": "2", - "value": "2" + "text": "1", + "value": "1" }, "datasource": { "type": "prometheus", @@ -1346,8 +1144,8 @@ { "current": { "selected": false, - "text": "INVENTORYQUEUE", - "value": "INVENTORYQUEUE" + "text": "TOPIC_1", + "value": "TOPIC_1" }, "datasource": { "type": "prometheus", @@ -1376,8 +1174,8 @@ { "current": { "selected": false, - "text": "1", - "value": "1" + "text": "0", + "value": "0" }, "datasource": { "type": "prometheus", @@ -1460,11 +1258,22 @@ "tagsQuery": "", "type": "query", "useTags": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "Prometheus" + }, + "filters": [], + "hide": 0, + "name": "Filters", + "skipUrlSync": false, + "type": "adhoc" } ] }, "time": { - "from": "now-30m", + "from": "now-15m", "to": "now" }, "timepicker": { @@ -1484,6 +1293,6 @@ "timezone": "", "title": "TxEventQ Monitor", "uid": "b6momtbWk", - "version": 2, + "version": 1, "weekStart": "" } \ No newline at end of file diff --git a/docker-compose/oracle/grant_permissions.sql b/docker-compose/oracle/grant_permissions.sql index fedd132..4d0bba0 100644 --- a/docker-compose/oracle/grant_permissions.sql +++ b/docker-compose/oracle/grant_permissions.sql @@ -1,4 +1,5 @@ alter session set container=freepdb1; +grant unlimited tablespace to pdbadmin; grant select_catalog_role to pdbadmin; grant execute on dbms_aq to pdbadmin; grant execute on dbms_aqadm to pdbadmin; diff --git a/docker-compose/txeventq-load/pom.xml b/docker-compose/txeventq-load/pom.xml new file mode 100644 index 0000000..4d283a8 --- /dev/null +++ b/docker-compose/txeventq-load/pom.xml @@ -0,0 +1,68 @@ + + + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.1 + + + com.example + txeventq-load + 0.0.1-SNAPSHOT + txeventq-load + Create some load to demo TxEventQ dashboard + + + + + + + + + + + + + + + 21 + + + + org.springframework.boot + spring-boot-starter-web + + + + com.oracle.database.spring + oracle-spring-boot-starter-aqjms + 23.4.0 + + + + com.oracle.database.spring + oracle-spring-boot-starter-ucp + 23.4.0 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/docker-compose/txeventq-load/src/main/java/com/example/txeventq_load/QueueConsumer.java b/docker-compose/txeventq-load/src/main/java/com/example/txeventq_load/QueueConsumer.java new file mode 100644 index 0000000..786a977 --- /dev/null +++ b/docker-compose/txeventq-load/src/main/java/com/example/txeventq_load/QueueConsumer.java @@ -0,0 +1,86 @@ +// Copyright (c) 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +package com.example.txeventq_load; + +import java.util.Random; + +import org.springframework.jms.annotation.JmsListener; +import org.springframework.stereotype.Component; + +@Component +public class QueueConsumer { + + private Random random = new Random(); + + @JmsListener(destination = "topic_0", containerFactory = "factory", concurrency = "1") + public void topic0(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + + @JmsListener(destination = "topic_1", containerFactory ="factory", concurrency = "1") + public void topic1(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + + @JmsListener(destination = "topic_2", containerFactory ="factory", concurrency = "1") + public void topic2(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + + @JmsListener(destination = "topic_3", containerFactory ="factory", concurrency = "1") + public void topic3(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + + @JmsListener(destination = "topic_4", containerFactory ="factory", concurrency = "1") + public void topic4(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + + @JmsListener(destination = "topic_5", containerFactory ="factory", concurrency = "1") + public void topic5(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + + @JmsListener(destination = "topic_6", containerFactory ="factory", concurrency = "1") + public void topic6(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + + @JmsListener(destination = "topic_7", containerFactory ="factory", concurrency = "1") + public void topic7(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + + @JmsListener(destination = "topic_8", containerFactory ="factory", concurrency = "1") + public void topic8(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + + @JmsListener(destination = "topic_9", containerFactory ="factory", concurrency = "1") + public void topic9(Object object) { + try { + Thread.sleep(random.nextInt(2000)+500); + } catch (InterruptedException ignore) {} + } + +} diff --git a/docker-compose/txeventq-load/src/main/java/com/example/txeventq_load/TxeventqLoadApplication.java b/docker-compose/txeventq-load/src/main/java/com/example/txeventq_load/TxeventqLoadApplication.java new file mode 100644 index 0000000..ee6a712 --- /dev/null +++ b/docker-compose/txeventq-load/src/main/java/com/example/txeventq_load/TxeventqLoadApplication.java @@ -0,0 +1,146 @@ +// Copyright (c) 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +package com.example.txeventq_load; + +import java.sql.Connection; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.jms.annotation.EnableJms; +import org.springframework.jms.config.DefaultJmsListenerContainerFactory; +import org.springframework.jms.config.JmsListenerContainerFactory; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.jms.support.converter.MappingJackson2MessageConverter; +import org.springframework.jms.support.converter.MessageConverter; +import org.springframework.jms.support.converter.MessageType; + +import jakarta.jms.ConnectionFactory; +import jakarta.jms.Destination; +import jakarta.jms.Session; +import jakarta.jms.TopicConnection; +import jakarta.jms.TopicConnectionFactory; +import jakarta.jms.TopicSession; +import lombok.extern.slf4j.Slf4j; +import oracle.jakarta.AQ.AQQueueTableProperty; +import oracle.jakarta.jms.AQjmsDestination; +import oracle.jakarta.jms.AQjmsFactory; +import oracle.jakarta.jms.AQjmsSession; + +@SpringBootApplication +@EnableJms +@Slf4j +public class TxeventqLoadApplication implements CommandLineRunner { + + private Random random = new Random(); + private int NUM_TOPICS = 10; + + @Autowired + private ConfigurableApplicationContext context; + + public static void main(String[] args) { + SpringApplication.run(TxeventqLoadApplication.class, args); + } + + @Bean + public MessageConverter jacksonJmsMessageConverter() { + MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); + converter.setTargetType(MessageType.TEXT); + converter.setTypeIdPropertyName("_type"); + return converter; + } + + + @Bean + public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) { + JmsTemplate jmsTemplate = new JmsTemplate(); + jmsTemplate.setConnectionFactory(connectionFactory); + jmsTemplate.setMessageConverter(jacksonJmsMessageConverter()); + return jmsTemplate; + } + + @Bean + public JmsListenerContainerFactory factory(ConnectionFactory connectionFactory, + DefaultJmsListenerContainerFactoryConfigurer configurer) { + DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); + // This provides all boot's default to this factory, including the message converter + configurer.configure(factory, connectionFactory); + // You could still override some of Boot's default if necessary. + return factory; + } + + @Override + public void run(String... args) throws Exception { + + JmsTemplate jmsTemplate = (JmsTemplate) context.getBean("jmsTemplate"); + assert (jmsTemplate != null); + + // create topics if they don't exist + for (int i = 0; i < NUM_TOPICS; i++) { + createTopic(i); + } + + // send some messages + while (true) { + jmsTemplate.convertAndSend("topic_" + random.nextInt(NUM_TOPICS), animals.get(random.nextInt(animals.size()))); + try { + Thread.sleep(random.nextInt(300)); + } catch (InterruptedException ignore) {} + } + + } + + public record Animal( + String name, + String size + ) {} + + public List animals = Arrays.asList( + new Animal("cat", "small"), + new Animal("dog", "medium"), + new Animal("horse", "large"), + new Animal("elephant", "extra large") + ); + + private void createTopic(int i) { + DataSource dataSource = (DataSource) context.getBean("dataSource"); + assert (dataSource != null); + + try { + TopicConnectionFactory tcf = AQjmsFactory.getTopicConnectionFactory(dataSource); + TopicConnection conn = tcf.createTopicConnection(); + conn.start(); + TopicSession session = (AQjmsSession) conn.createSession(true, Session.AUTO_ACKNOWLEDGE); + + // create properties + AQQueueTableProperty props = new AQQueueTableProperty("SYS.AQ$_JMS_TEXT_MESAGE"); + props.setMultiConsumer(true); + props.setPayloadType("SYS.AQ$_JMS_TEXT_MESSAGE"); + + // create queue table, topic and start it + Destination myTeq = ((AQjmsSession) session).createJMSTransactionalEventQueue("topic_" + i, false); + ((AQjmsDestination) myTeq).start(session, true, true); + + // cleanup + session.close(); + conn.close(); + + } catch (Exception e) { + if (e.getMessage().contains("already exists")) { + log.info("topic already exists"); + } else { + log.error("error talking to databsae", e); + } + } + } +} diff --git a/docker-compose/txeventq-load/src/main/resources/application.yaml b/docker-compose/txeventq-load/src/main/resources/application.yaml new file mode 100644 index 0000000..77447bd --- /dev/null +++ b/docker-compose/txeventq-load/src/main/resources/application.yaml @@ -0,0 +1,19 @@ +spring: + application: + name: txeventq-load + threads: + virtual: + enabled: true + + datasource: + url: jdbc:oracle:thin:@//172.23.0.3:1521/freepdb1 + username: pdbadmin + password: Welcome12345 + driver-class-name: oracle.jdbc.OracleDriver + type: oracle.ucp.jdbc.PoolDataSource + oracleucp: + connection-factory-class-name: oracle.jdbc.pool.OracleDataSource + connection-pool-name: TollReaderConnectionPool + initial-pool-size: 15 + min-pool-size: 10 + max-pool-size: 30 \ No newline at end of file diff --git a/vault/vault.go b/vault/vault.go index 7338173..7ca2599 100755 --- a/vault/vault.go +++ b/vault/vault.go @@ -1,5 +1,5 @@ -// Copyright (c) 2023, Oracle and/or its affiliates. -// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.package vault +// Copyright (c) 2023, 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. package vault