Skip to main content

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:
1

Generate unique subscriber ID

Creates a subscriber name like SUB_A1B2C3D4 using a random identifier
2

Register with queue

Calls OMNI_TRACER_API.Register_Subscriber() to add the subscriber to the queue
3

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');
  1. Message is enqueued to OMNI_TRACER_QUEUE
  2. Oracle AQ automatically creates a copy for each registered subscriber
  3. Each copy is placed in the subscriber’s dedicated queue partition
  4. 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

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.

On Different Machines

1

Configure each machine

Create settings.json on each machine pointing to the same database:
Machine A: settings.json
{
    "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.
2

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
3

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;
/

Performance Implications

Message Replication Overhead

Each subscriber adds overhead to the queue system:
SubscribersMessage CopiesEstimated Overhead
11Baseline
33~2x baseline
55~3-4x baseline
1010~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

  1. Limit subscribers: Keep active subscribers under 10 for optimal performance
  2. Clean up on exit: Always allow OmniView to shut down gracefully (Ctrl+C)
  3. 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';
    
  4. 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

Build docs developers (and LLMs) love