Overview
OmniView supports multiple concurrent subscribers connecting to the same Oracle database. Each subscriber receives an independent copy of all trace messages, enabling team collaboration, distributed debugging, and production monitoring without interference.
Why Multiple Subscribers?
Multiple OmniView instances are useful for:
Team Collaboration Multiple developers can monitor the same database independently during development
Production Monitoring Separate instances for real-time monitoring and log archival without conflicts
Distributed Systems Monitor different application components or microservices from dedicated consoles
Testing & Development Run OmniView on both test and development environments simultaneously
Architecture Overview
OmniView uses Oracle Advanced Queuing (AQ) with multi-consumer queues and a sharded queue architecture to efficiently distribute messages to multiple subscribers.
Message Distribution Model
┌─────────────────────────────────────────────────────────────┐
│ PL/SQL Code │
│ OMNI_TRACER_API.Trace_Message() │
└────────────────────┬────────────────────────────────────────┘
│
│ Enqueue (Broadcast)
▼
┌─────────────────────────────────────────────────────────────┐
│ OMNI_TRACER_QUEUE (Sharded) │
│ │
│ Shard 1 Shard 2 Shard 3 Shard 4 │
│ │ │ │ │ │
│ └──────────┴──────────┴──────────┘ │
│ Multi-Consumer Broadcast │
└─────────┬──────────────┬──────────────┬─────────────────────┘
│ │ │
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Client A│ │ Client B│ │ Client C│
│ SUB_AAA │ │ SUB_BBB │ │ SUB_CCC │
└─────────┘ └─────────┘ └─────────┘
(Copy 1) (Copy 2) (Copy 3)
Each subscriber receives an independent copy of every message. One subscriber’s consumption doesn’t affect message availability for others.
How It Works
1. Automatic Subscriber Registration
When OmniView starts, it automatically:
Generate unique subscriber ID
Creates a subscriber name like SUB_A1B2C3D4 using a random identifier
Register with queue
Calls OMNI_TRACER_API.Register_Subscriber() to add the subscriber to the queue
Start listening
Begins blocking dequeue loop waiting for messages
2. Message Broadcasting
When Trace_Message() is called:
OMNI_TRACER_API . Trace_Message ( 'Processing order #12345' , 'INFO' );
Message is enqueued to OMNI_TRACER_QUEUE
Oracle AQ automatically creates a copy for each registered subscriber
Each copy is placed in the subscriber’s dedicated queue partition
Subscribers dequeue their copies independently
The enqueue operation is fire-and-forget from the application perspective. Oracle handles message replication internally.
3. Independent Consumption
Each OmniView instance:
Maintains its own blocking dequeue connection
Receives messages in real-time as they arrive
Dequeues messages independently without affecting other subscribers
Can stop, restart, or disconnect without impacting others
Running Multiple Instances
On the Same Machine
Using Multiple Terminals
Using tmux/screen
Open separate terminal windows and run OmniView in each: Terminal 1: cd ~/omniview
./omniview
# Output: Registered Subscriber: SUB_A1B2C3D4
Terminal 2: cd ~/omniview
./omniview
# Output: Registered Subscriber: SUB_E5F6G7H8
Both instances will receive all trace messages independently. Split your terminal using tmux: # Start tmux
tmux
# Run first instance
./omniview
# Split window (Ctrl+B, then %)
# In new pane, run second instance
./omniview
# Split again for more instances (Ctrl+B, then ")
./omniview
On Different Machines
Configure each machine
Create settings.json on each machine pointing to the same database : {
"DatabaseSettings" : {
"Database" : "FREEPDB1" ,
"Host" : "db-server.company.com" ,
"Port" : 1521 ,
"Username" : "IFSAPP" ,
"Password" : "ifsapp" ,
"Default" : true
},
"ClientSettings" : {
"EnableUtf8" : false
}
}
Use the same configuration on Machine B, C, etc.
Start OmniView on each machine
# Machine A
./omniview
# Registered Subscriber: SUB_A1B2C3D4
# Machine B
./omniview
# Registered Subscriber: SUB_E5F6G7H8
# Machine C
./omniview
# Registered Subscriber: SUB_I9J0K1L2
Verify message distribution
Send a test trace from SQL*Plus: BEGIN
OMNI_TRACER_API . Trace_Message ( 'Test broadcast message' , 'INFO' );
END ;
/
This message should appear on all three machines simultaneously.
Use Cases
Development Team Monitoring
Scenario: Three developers working on the same application:
Developer A monitors order processing
Developer B monitors payment gateway integration
Developer C monitors inventory updates
Each runs OmniView on their workstation and uses grep to filter relevant messages:
# Developer A
./omniview | grep "ORDER"
# Developer B
./omniview | grep "PAYMENT"
# Developer C
./omniview | grep "INVENTORY"
Production Monitoring and Archival
Scenario: Production database with compliance requirements:
Monitor Console displays real-time traces for operators
Archive Service saves all traces to long-term storage
Alert Service watches for ERROR level messages and sends notifications
# Monitor console (real-time display)
./omniview
# Archive service (save to rotating log files)
./omniview | tee -a /var/log/omniview/traces- $( date +%Y%m%d ) .log
# Alert service (send errors to monitoring system)
./omniview | grep "\[ERROR\]" | ./send-to-monitoring.sh
Multi-Environment Testing
Scenario: QA team testing application across environments:
# Terminal 1: DEV database
cp settings-dev.json settings.json
./omniview
# Terminal 2: TEST database
cp settings-test.json settings.json
./omniview
# Terminal 3: STAGING database
cp settings-staging.json settings.json
./omniview
Subscriber Management
Viewing Active Subscribers
Query Oracle to see all registered subscribers:
SELECT
queue_name,
consumer_name,
address ,
protocol
FROM
user_queue_subscribers
WHERE
queue_name = 'OMNI_TRACER_QUEUE'
ORDER BY
consumer_name;
Output:
QUEUE_NAME CONSUMER_NAME ADDRESS PROTOCOL
------------------ --------------- --------- --------
OMNI_TRACER_QUEUE SUB_A1B2C3D4 NULL 0
OMNI_TRACER_QUEUE SUB_E5F6G7H8 NULL 0
OMNI_TRACER_QUEUE SUB_I9J0K1L2 NULL 0
Manual Subscriber Registration
While OmniView handles this automatically, you can manually register subscribers:
BEGIN
OMNI_TRACER_API . Register_Subscriber ( 'SUB_MANUAL_TEST' );
END ;
/
Manually registered subscribers must be cleaned up manually. OmniView auto-registers subscribers are managed automatically.
Removing Orphaned Subscribers
If OmniView crashes without proper cleanup, subscribers may remain registered:
DECLARE
v_subscriber SYS . AQ $_AGENT;
BEGIN
v_subscriber : = SYS . AQ $_AGENT( 'SUB_ORPHANED_ID' , NULL , NULL );
DBMS_AQADM . REMOVE_SUBSCRIBER (
queue_name => 'OMNI_TRACER_QUEUE' ,
subscriber => v_subscriber
);
COMMIT ;
END ;
/
Message Replication Overhead
Each subscriber adds overhead to the queue system:
Subscribers Message Copies Estimated Overhead 1 1 Baseline 3 3 ~2x baseline 5 5 ~3-4x baseline 10 10 ~6-8x baseline
For most applications, 3-5 concurrent subscribers have negligible performance impact. Oracle’s sharded queue architecture scales efficiently.
Sharding Benefits
The OMNI_TRACER_QUEUE is configured with 4 shards (configurable):
DBMS_AQADM . SET_QUEUE_PARAMETER (
queue_name => 'OMNI_TRACER_QUEUE' ,
param_name => 'SHARD_NUM' ,
param_value => 4
);
Sharding provides:
Parallel processing : Multiple subscribers can dequeue concurrently
Reduced contention : Each shard has independent locks
Better throughput : Distributes load across multiple queue partitions
Best Practices
Limit subscribers : Keep active subscribers under 10 for optimal performance
Clean up on exit : Always allow OmniView to shut down gracefully (Ctrl+C)
Monitor queue depth : Check for message buildup if subscribers are slow
SELECT queue_name, enqueued_msgs, dequeued_msgs
FROM v$aq
WHERE queue_name = 'OMNI_TRACER_QUEUE' ;
Use message expiration : Configure message retention to prevent indefinite accumulation
Limitations and Considerations
Broadcast Only (Currently)
In the current architecture, all subscribers receive all messages . Targeted message delivery to specific subscribers requires additional configuration (see future enhancements).
No Message Filtering
Filtering must be done client-side:
# Each client filters as needed
./omniview | grep "ORDER_SERVICE"
Database-level filtering is not currently supported but may be added in future versions.
Subscriber Lifecycle
Subscribers are automatically cleaned up on graceful shutdown, but:
Crashes may leave orphaned subscribers
Network failures may cause temporary disconnections
Database restarts require re-registration
OmniView handles reconnection automatically with exponential backoff.
Advanced Configuration
Custom Subscriber Names
For production deployments, you may want meaningful subscriber names:
// Modify internal/service/subscribers/subscriber_service.go
func ( ss * SubscriberService ) RegisterSubscriber () ( domain . Subscriber , error ) {
// Instead of random ID, use:
hostname , _ := os . Hostname ()
subscriberName := fmt . Sprintf ( "SUB_ %s " , strings . ToUpper ( hostname ))
// Register with custom name
// ...
}
This creates subscribers like:
SUB_DEV_WORKSTATION_1
SUB_PROD_MONITOR
SUB_QA_SERVER_02
Adjusting Shard Count
For high-throughput environments with many subscribers:
BEGIN
DBMS_AQADM . STOP_QUEUE ( 'OMNI_TRACER_QUEUE' );
DBMS_AQADM . SET_QUEUE_PARAMETER (
queue_name => 'OMNI_TRACER_QUEUE' ,
param_name => 'SHARD_NUM' ,
param_value => 8 -- Increase from default 4
);
DBMS_AQADM . START_QUEUE ( 'OMNI_TRACER_QUEUE' );
END ;
/
Increasing shards improves parallelism but uses more database resources. Test with your workload before changing production settings.
Troubleshooting Multi-Subscriber Issues
Only One Instance Receives Messages
This suggests the queue is not in multi-consumer mode:
-- Verify multi-consumer is enabled
SELECT queue_name, queue_type, max_consumers
FROM user_queues
WHERE queue_name = 'OMNI_TRACER_QUEUE' ;
-- Should show max_consumers = UNLIMITED or > 1
If not, recreate the queue:
BEGIN
DBMS_AQADM . CREATE_SHARDED_QUEUE (
queue_name => 'OMNI_TRACER_QUEUE' ,
multiple_consumers => TRUE, -- Must be TRUE
queue_payload_type => 'OMNI_TRACER_PAYLOAD_TYPE'
);
END ;
/
Messages Delayed on Some Subscribers
Check for network latency or processing bottlenecks:
-- Check message lag per subscriber
SELECT
consumer_name,
COUNT ( * ) as pending_messages,
MIN (enq_time) as oldest_message
FROM
aq$omni_tracer_queue
WHERE
consumer_name IS NOT NULL
GROUP BY
consumer_name;
Subscriber Registration Fails
Check permissions:
-- Verify AQ privileges
SELECT * FROM user_sys_privs
WHERE privilege LIKE '%AQ%' ;
-- Should include:
-- EXECUTE on DBMS_AQADM
-- EXECUTE on DBMS_AQ
Next Steps
Configuration Guide Configure database connections and client settings
Using the Tracer Learn how to send and filter trace messages