Bridge Service Configuration Guide#
The MA DataPlatforms Bridge service uses multiple configuration sections to control various aspects of data streaming, processing, and integration. This guide provides comprehensive documentation for all configuration sections.
Configuration File Structure#
The main configuration file is typically AppConfig.json and contains the following top-level sections:
{
"StreamApiConfig": { ... },
"StreamSelectionConfig": { ... },
"BridgeConfig": { ... },
"EssentialsConfig": { ... },
"RdaConfig": { ... },
"Serilog": { ... }
}
1. StreamApiConfig#
Controls the Stream API integration and Kafka broker connectivity.
Properties#
| Property | Type | Default | Description |
|---|---|---|---|
StreamCreationStrategy |
int/enum | 2 | Strategy for creating Kafka topics/streams • 1 = PartitionBased• 2 = TopicBased (recommended) |
BrokerUrl |
string | "localhost:9092" | Kafka broker connection string |
PartitionMappings |
array | [] | Partition mapping configurations (PartitionBased only) |
IntegrateSessionManagement |
boolean | true | Enable session management integration |
IntegrateDataFormatManagement |
boolean | true | Enable data format management integration |
UseRemoteKeyGenerator |
boolean | false | Use remote key generator service |
RemoteKeyGeneratorServiceAddress |
string | "" | URL of remote key generator service |
InitialisationTimeoutSeconds |
int | 1 | Timeout in seconds for Stream API init |
Domain |
string | "" | Optional domain specification |
Example Configuration#
{
"StreamApiConfig": {
"StreamCreationStrategy": 2,
"BrokerUrl": "kafka-broker.company.com:9092",
"PartitionMappings": [],
"IntegrateSessionManagement": true,
"IntegrateDataFormatManagement": true,
"UseRemoteKeyGenerator": false,
"RemoteKeyGeneratorServiceAddress": "",
"InitialisationTimeoutSeconds": 1,
"Domain": "Telemetry"
}
}
Stream Creation Strategy Explained#
The Bridge service works with Stream API's two streaming strategies. Your choice affects how Bridge streams are mapped to Kafka topics.
Topic-Based Strategy (StreamCreationStrategy = 2)#
Each stream from the Bridge service maps to its own Kafka topic. This is simpler and recommended for most use cases.
How Mapping Works:
- Bridge uses
StreamSelectionConfigto determine stream names. - Each unique stream name creates a separate Kafka topic.
- Topic naming:
{Domain}.Data.{StreamName}
Example Scenario
Bridge Configuration:
{
"StreamApiConfig": {
"StreamCreationStrategy": 2,
"Domain": "Production"
},
"StreamSelectionConfig": {
"Auto": false,
"Mappings": [
{ "AppName": "Engine*", "Stream": "EngineTelemetry" },
{ "AppName": "Chassis*", "Stream": "ChassisTelemetry" },
{ "AppName": "Aero*", "Stream": "AeroTelemetry" }
]
}
}
Resulting Kafka Topics:
* Production.Data.EngineTelemetry (All Engine app groups)
* Production.Data.ChassisTelemetry (All Chassis app groups)
* Production.Data.AeroTelemetry (All Aero* app groups)
Use Topic-Based When:
- You have fewer than 100 unique streams.
- You want simple debugging (each stream has its own topic).
- Topic limits are not a concern.
- Message time alignment across streams is not important, or will be handled at the consumer level (note: Kafka does not align messages between topics).
Partition-Based Strategy (StreamCreationStrategy = 1)#
Multiple streams share a single Kafka topic but are distributed across different partitions. Requires explicit partition mappings in StreamApiConfig.
How Mapping Works:
- Bridge uses
StreamSelectionConfigto determine stream names. - Stream API uses
PartitionMappingsto assign each stream to a partition. - All streams share the same topic:
{Domain}.Data.MainDataSource. - IMPORTANT: Partition 0 is reserved by Stream API.
Example Scenario
Bridge Configuration:
{
"StreamApiConfig": {
"StreamCreationStrategy": 1,
"Domain": "Production",
"PartitionMappings": [
{ "StreamIdentifier": "EngineTelemetry", "Partition": 1 },
{ "StreamIdentifier": "ChassisTelemetry", "Partition": 2 },
{ "StreamIdentifier": "AeroTelemetry", "Partition": 3 },
{ "StreamIdentifier": "BrakeTelemetry", "Partition": 4 }
]
},
"StreamSelectionConfig": {
"Auto": false,
"Mappings": [
{ "AppName": "Engine*", "Stream": "EngineTelemetry" },
{ "AppName": "Chassis*", "Stream": "ChassisTelemetry" },
{ "AppName": "Aero*", "Stream": "AeroTelemetry" },
{ "AppName": "Brake*", "Stream": "BrakeTelemetry" }
]
}
}
Resulting Kafka Topic with Partitions:
Topic: Production.Data.MainDataSource
* Partition 0: [Reserved by Stream API]
* Partition 1: EngineTelemetry data
* Partition 2: ChassisTelemetry data
* Partition 3: AeroTelemetry data
* Partition 4: BrakeTelemetry data
Critical Rules for Partition-Based
- Stream names in
StreamSelectionConfigMUST matchStreamIdentifierinPartitionMappings. - Partition 0 is reserved - all mappings must use partition 1 and above.
- Each stream must have a unique partition number.
- Kafka topic must be created with enough partitions (max partition number + 1).
Use Partition-Based When:
- You have hundreds or thousands of streams.
- Kafka topic limits are a concern.
- You need better resource utilization.
- You need better resource utilization.
- You need time-aligned data across multiple streams - Kafka guarantees message order only within a single partition, so partition-based allows all streams to share one topic with proper temporal alignment.
Time-Aligned Data Consideration
For both Topic-Based and Partition-Based strategies: If you need time-aligned data across multiple application groups, map all of them to a single stream name in StreamSelectionConfig. This ensures:
- Topic-Based (Strategy 2): All data goes to one Kafka topic with aligned timestamps.
- Partition-Based (Strategy 1): All data goes to one partition within the topic with aligned timestamps.
Example for time-aligned data:
{
"StreamSelectionConfig": {
"Auto": false,
"Mappings": [
{ "AppName": "Engine*", "Stream": "VehicleTelemetry" },
{ "AppName": "Chassis*", "Stream": "VehicleTelemetry" },
{ "AppName": "Aero*", "Stream": "VehicleTelemetry" },
{ "AppName": "Brake*", "Stream": "VehicleTelemetry" }
]
}
}
Stream Mapping Flow#
- Data arrives at Bridge with
AppName(e.g., "EngineData") StreamSelectionConfigmapsAppNameto Stream- Example: "EngineData" -> matches "Engine*" -> "EngineTelemetry"
- Stream API receives "EngineTelemetry" stream
StreamCreationStrategydetermines Kafka destination:- Topic-Based (Strategy 2): Writes to Kafka topic
Production.Data.EngineTelemetry. - Partition-Based (Strategy 1):
- Looks up "EngineTelemetry" in
PartitionMappings. - Finds Partition 1.
- Writes to
Production.Data.MainDataSource, Partition 1.
- Looks up "EngineTelemetry" in
- Topic-Based (Strategy 2): Writes to Kafka topic
2. StreamSelectionConfig#
Controls how data streams are mapped from application groups to Stream API streams, including wildcard pattern matching support.
Properties#
| Property | Type | Default | Description |
|---|---|---|---|
Auto |
boolean | true | Automatically map app names to stream names without transformation |
Mappings |
array | [] | Custom mappings from app names to streams with wildcard support (when Auto=false) |
Mappings Structure#
Each mapping entry contains:
| Field | Type | Description |
|---|---|---|
AppName |
string | Application group name or pattern (supports wildcards: *) |
Stream |
string | Target stream name in Stream API |
Wildcard Pattern Matching#
The AppName field supports wildcard patterns using the * character:
- Exact match:
"EngineData"- matches only "EngineData" - Prefix match:
"Engine*"- matches "EngineData", "EngineTemp", "EnginePressure" - Suffix match:
"*Telemetry"- matches "EngineTelemetry", "ChassisTelemetry" - Contains:
"*_Data_*"- matches any app name containing "Data"
Pattern Evaluation Rules:
- Patterns are evaluated in order of definition.
- First matching pattern wins.
- Case-insensitive matching.
- Results are cached for performance.
Example Configurations#
Auto Mode (Simple)#
{
"StreamSelectionConfig": {
"Auto": true
}
}
Manual Mapping (No Wildcards)#
{
"StreamSelectionConfig": {
"Auto": false,
"Mappings": [
{
"AppName": "EngineData",
"Stream": "engine-telemetry-stream"
},
{
"AppName": "ChassisData",
"Stream": "chassis-telemetry-stream"
}
]
}
}
Wildcard Mapping (Flexible)#
{
"StreamSelectionConfig": {
"Auto": false,
"Mappings": [
{
"AppName": "Engine*",
"Stream": "engine-telemetry-stream"
},
{
"AppName": "Chassis*",
"Stream": "chassis-telemetry-stream"
},
{
"AppName": "*Telemetry",
"Stream": "general-telemetry-stream"
},
{
"AppName": "Aero_*_Data",
"Stream": "aerodynamics-stream"
}
]
}
}
Best Practices#
- Ordering Matters: Place more specific patterns before general ones.
- Auto Mode: Use when stream names match app group names exactly.
- Wildcards: Use to reduce configuration complexity when dealing with many similar app groups.
3. BridgeConfig#
Controls core Bridge service behavior including processing units, data handling, and flow control strategies.
Properties#
| Property | Type | Default | Description |
|---|---|---|---|
DataSource |
string | "Default" | Name identifier for the data source |
UseStringIdentifier |
boolean | false | Use string-based identifiers instead of numeric IDs |
NumberWritingUnit |
int | 8 | Number of parallel writing units (threads) for Stream API |
NumberProcessingUnit |
int | 4 | Number of parallel processing units for data decoding |
AdsTimeoutInSeconds |
int | 720 | Timeout in seconds for detecting session stop when no data is received from ADS (ATLAS Data Server) |
ProcessFlow |
enum | SequentialAll | Data processing flow strategy (see below for details) |
ProcessFlow Strategies#
The ProcessFlow property controls how the Bridge service handles data flow and backpressure:
SequentialAll (Default)#
- Value:
"SequentialAll"or0 - Behavior: Processes all data sequentially without dropping any packets
- Use when: Data integrity is critical and you need to ensure every packet is processed
- Impact: May experience backpressure if downstream systems are slow
DropOldest#
- Value:
"DropOldest"or1 - Behavior: Drops oldest unprocessed data when buffers are full, prioritizing recent data
- Use when: Real-time data is more important than historical completeness
- Impact: Better performance under load, but some data may be dropped during high traffic
- Note: Applies per-session dropping strategy to maintain data freshness
Example Configuration#
{
"BridgeConfig": {
"DataSource": "RaceTrack01",
"UseStringIdentifier": true,
"NumberWritingUnit": 16,
"NumberProcessingUnit": 8,
"AdsTimeoutInSeconds": 600,
"ProcessFlow": "SequentialAll"
}
}
Example with DropOldest Flow#
{
"BridgeConfig": {
"DataSource": "LiveTelemetry",
"UseStringIdentifier": true,
"NumberWritingUnit": 24,
"NumberProcessingUnit": 12,
"AdsTimeoutInSeconds": 720,
"ProcessFlow": "DropOldest"
}
}
Performance Tuning#
NumberWritingUnit: Increase for higher throughput to Stream API. Higher values use more CPU.NumberProcessingUnit: Controls parallel data decoding/processing. Increase for multi-core systems.AdsTimeoutInSeconds: Controls how long the Bridge waits without receiving data before considering a session stopped. Default is 720 seconds (12 minutes). Reduce for faster session timeout detection, increase if you expect longer gaps in data transmission.ProcessFlow: ChooseSequentialAllwhen data completeness is critical, orDropOldestwhen real-time performance is more important than historical completeness.
4. EssentialsConfig#
Configuration files (CFG) and Parameter Group Values (PGV) are essential for data decoding.
Note
When using integrated Windows Bridge with ADS, these files are automatically retrieved from ADS (ATLAS Data Server) and do not need to be manually configured.
Properties#
| Property | Type | Description |
|---|---|---|
CfgDirectoryPaths |
string[] | Array of directory paths containing CFG configuration files |
PgvDirectoryPaths |
string[] | Array of directory paths containing PGV parameter files |
RemoteConfigIndexerUrl |
string? | Optional URL for remote configuration indexer service |
Note: The
RemoteConfigIndexerUrloption is only used when a centralized configuration indexer service is deployed and accessible. When configured, the Bridge will query that URL to retrieve CFG and PGV info from the remote service. If the remote service is not available or no info is returned, it will fall back to using the local directories.
Example Configuration#
{
"EssentialsConfig": {
"CfgDirectoryPaths": [
"C:\\Data\\Logging\\AutoConfig",
"C:\\Data\\Logging\\ManualConfig"
],
"PgvDirectoryPaths": [
"C:\\Data\\Parameters\\PGVs",
"C:\\SharedConfigs\\PGVs"
],
"RemoteConfigIndexerUrl": null
}
}
Using Remote Config Indexer#
For centralized configuration management, you can specify a remote configuration indexer service URL. This allows the Bridge to query that URL to fetch configuration files from a central server. If the remote service is not available or no info is returned, it will fall back to using the local directories:
{
"EssentialsConfig": {
"CfgDirectoryPaths": [],
"PgvDirectoryPaths": [],
"RemoteConfigIndexerUrl": "http://config-server.company.com:5050"
}
}
Benefits of Remote Config Indexer: * Reduced file searching and querying time - file locations are cached for faster retrieval, minimizing I/O overhead
Hybrid Configuration:
You can also use both local directories and remote indexer. If the remote service is unavailable, the Bridge will fall back to local directories:
{
"EssentialsConfig": {
"CfgDirectoryPaths": ["C:\\Data\\Configs\\CFG"],
"PgvDirectoryPaths": ["C:\\Data\\Configs\\PGV"],
"RemoteConfigIndexerUrl": "http://config-server.company.com:5050"
}
}
5. RdaConfig#
Reduced Data Access (RDA) configuration for reading telemetry data files.
Properties#
| Property | Type | Description |
|---|---|---|
PulFilesSearchPaths |
string[] | Array of directory paths to search for PUL files |
Example Configuration#
{
"RdaConfig": {
"PulFilesSearchPaths": [
"C:\\RDA\\SessionData\\2026",
"C:\\RDA\\Archive",
"\\\\FileServer\\RDA\\Shared"
]
}
}
6. Serilog Configuration#
Structured logging configuration using the Serilog framework.
Configuration Priority#
The Bridge service uses the following priority order for logging configuration:
- Serilog section in
AppConfig.json(if present) - Full customization via JSON. LOG_FILE_PATHenvironment variable or-lcommand-line argument.- Default - Falls back to
Logs/bridge-svc-log.txt.
Important
If you include a Serilog section in your AppConfig.json, you have full control over logging configuration. Without it, the service uses built-in defaults.
Basic Structure#
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{ "Name": "Console", "Args": { ... } },
{ "Name": "File", "Args": { ... } }
],
"Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"]
}
}
Log Levels#
- Verbose: Very detailed, trace-level information.
- Debug: Debugging information.
- Information: General informational messages (recommended default).
- Warning: Warnings that don't stop operation.
- Error: Errors and exceptions.
- Fatal: Critical failures causing shutdown.
Console Sink Configuration#
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}"
}
}
File Sink Configuration#
{
"Name": "File",
"Args": {
"path": "C:\\Logs\\bridge-service-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 30,
"fileSizeLimitBytes": 104857600,
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] {Message:lj}{NewLine}{Exception}"
}
}
Tip
When using the Serilog section in AppConfig.json, the file sink path is fully customisable.
File Sink Configuration#
{
"Name": "File",
"Args": {
"path": "C:\\Logs\\bridge-service-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 30,
"fileSizeLimitBytes": 104857600,
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] {Message:lj}{NewLine}{Exception}"
}
}
Tip
When using the Serilog section in AppConfig.json, the file sink path is fully customisable.
Complete Configuration Example#
{
"StreamApiConfig": {
"StreamCreationStrategy": 2,
"BrokerUrl": "kafka-prod.company.com:9094",
"PartitionMappings": [],
"IntegrateSessionManagement": true,
"IntegrateDataFormatManagement": true,
"UseRemoteKeyGenerator": false,
"RemoteKeyGeneratorServiceAddress": "",
"BatchingResponses": false,
"InitialisationTimeoutSeconds": 1,
"Domain": "motorsport"
},
"StreamSelectionConfig": {
"Auto": false,
"Mappings": [
{ "AppName": "Engine*", "Stream": "engine-telemetry" },
{ "AppName": "Chassis*", "Stream": "chassis-telemetry" },
{ "AppName": "Aero*", "Stream": "aerodynamics-telemetry" },
{ "AppName": "*Telemetry", "Stream": "general-telemetry" }
]
},
"BridgeConfig": {
"DataSource": "TestTrack_Simulator",
"UseStringIdentifier": true,
"NumberWritingUnit": 16,
"NumberProcessingUnit": 8,
"AdsTimeoutInSeconds": 600,
"ProcessFlow": "SequentialAll"
},
"EssentialsConfig": {
"CfgDirectoryPaths": [
"C:\\ProgramData\\ATLAS\\Configs",
"\\\\FileServer\\SharedConfigs\\CFG"
],
"PgvDirectoryPaths": [
"C:\\ProgramData\\ATLAS\\Parameters",
"\\\\FileServer\\SharedConfigs\\PGV"
],
"RemoteConfigIndexerUrl": null
},
"RdaConfig": {
"PulFilesSearchPaths": [
"C:\\RDA\\Sessions\\2026",
"\\\\FileServer\\RDA\\Archive"
]
},
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "C:\\Logs\\bridge-service-.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 30,
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss}] [{Level:u3}] {Message:lj}{NewLine}{Exception}"
}
}
]
}
}
Troubleshooting#
Common Configuration Issues#
- Issue: Stream API fails to initialize
- Check
BrokerUrlis correct and accessible. - Verify Kafka broker is running.
- Increase
InitialisationTimeoutSeconds.
- Check
- Issue: Data not decoding correctly
- Verify CFG files exist in
CfgDirectoryPaths. - Check PGV files are present in
PgvDirectoryPaths.
- Verify CFG files exist in
- Issue: Stream mapping not working
- Verify
Autois set tofalsewhen using custom mappings. - Check wildcard patterns/order.
- Verify
- Issue: Performance problems
- Increase
NumberWritingUnit/NumberProcessingUnit. - Consider using
ProcessFlow: "DropOldest"if real-time data is more important than completeness.
- Increase
- Issue: Data is being dropped
- Check if
ProcessFlowis set to"DropOldest". This is the expected behavior when buffers are full. - If data completeness is critical, change to
"SequentialAll". - Alternatively, increase
NumberWritingUnitandNumberProcessingUnitto improve throughput.
- Check if
- Issue: Session stops prematurely or doesn't stop
- Adjust
AdsTimeoutInSecondsbased on your data streaming pattern. - Default (720 seconds / 12 minutes) works for most scenarios.
- Reduce for faster timeout detection in live scenarios.
- Increase if you have legitimate gaps in data transmission.
- Adjust
- Issue: Remote Config Indexer not working
- Verify
RemoteConfigIndexerUrlis correct and accessible. - Check network connectivity to the config server.
- Ensure the configuration indexer service is running.
- Add local
CfgDirectoryPathsandPgvDirectoryPathsas backup.
- Verify
Resource Requirements
Increasing these values requires more system resources (CPU and memory). Setting values too high on smaller machines may lead to deadlock or threadpool starvation. Recommended settings for an 8-core machine with 16GB RAM:
NumberProcessingUnit: 12NumberWritingUnit: 24