Migrate monitors from Monte Carlo to SYNQ (Coalesce Quality) with a single command.
Project description
mc-to-synq
Migrate your data observability monitors from Monte Carlo to SYNQ (Coalesce Quality) with a single CLI.
Built from a production migration of 200+ monitors across a Snowflake data platform. Handles the full lifecycle: extract monitors from MC's GraphQL API, convert them to SYNQ-compatible formats, deploy via SYNQ's REST API, and clean up when you need to start over.
What it does
mc-to-synq solves three problems that make MC-to-SYNQ migrations painful:
1. Monitor extraction is messy. Monte Carlo stores monitors across three different GraphQL endpoints (getMonitors, getCustomRules, getAllUserDefinedMonitorsV2) with inconsistent schemas that change between versions. mc-to-synq introspects the MC schema at runtime to discover current field names, then merges all sources into a single unified export.
2. SQL conventions differ. MC custom SQL monitors return aggregate values and compare against thresholds. SYNQ SQL Tests expect the opposite: a query that returns 0 rows on success and rows on failure (the dbt convention). mc-to-synq analyzes each SQL statement, determines whether wrapping is needed, and handles the conversion automatically. CTE-based queries, HAVING clauses, NOT EXISTS patterns, and COUNT-based checks are all handled with appropriate flags for manual review when the analysis is ambiguous.
3. SYNQ does not auto-monitor views. If your data warehouse is view-heavy (which most analytics layers are), SYNQ's deployment rules silently skip them because they rely on INFORMATION_SCHEMA, which excludes views. mc-to-synq generates OOTB freshness, volume, and duplicate-detection monitors for every entity -- views included -- using SYNQ's BatchCreateMonitor REST API. Timestamp columns and business keys are resolved automatically via SYNQ's schema and constraint APIs.
Installation
pip install mc-to-synq
Or install from source:
git clone https://github.com/RyanSchlenz/mc-to-synq.git
cd mc-to-synq
pip install -e .
Requires Python 3.10+.
Quick start
1. Generate a config file
mc-to-synq init
This creates mc-to-synq.yaml in your current directory with annotated defaults. Open it and fill in:
- Your Snowflake coordinates (account, database, schema)
- Your SYNQ integration UUID (from Settings > Integrations)
- Entity filter prefixes to target the schemas you want to migrate
2. Set credentials
Monte Carlo credentials come from ~/.mcd/profiles.ini (the standard MC CLI config) or environment variables:
export MC_API_ID="your_mc_id"
export MC_API_TOKEN="your_mc_token"
SYNQ credentials are always environment variables:
export SYNQ_CLIENT_ID="your_client_id"
export SYNQ_CLIENT_SECRET="your_client_secret"
Create SYNQ API credentials at: Settings > API > Add client. Required scopes: Edit SQL Tests, Edit Automatic Monitors, Edit Custom Monitors.
3. Test connections
mc-to-synq status
4. Run the full migration
mc-to-synq migrate-all --dry-run
This extracts from MC, converts everything, generates payloads, and stops before deploying. Review the output files, then run without --dry-run to deploy.
Commands
Pipeline commands
| Command | Description |
|---|---|
mc-to-synq migrate-all |
Full pipeline: extract, convert, deploy |
mc-to-synq migrate-all --dry-run |
Full pipeline without deployment |
Step-by-step commands
For more control, run each step independently:
| Command | Description |
|---|---|
mc-to-synq extract |
Pull all monitors from MC, filter, save to JSON |
mc-to-synq migrate sql-tests |
Convert MC SQL monitors to SYNQ SQL Test payloads |
mc-to-synq migrate ootb |
Generate OOTB freshness/volume/duplicate monitors |
mc-to-synq migrate yaml |
Export monitors-as-code YAML for synq-monitors CLI |
mc-to-synq deploy sql-tests |
Push SQL Tests to SYNQ |
mc-to-synq deploy ootb |
Push OOTB monitors to SYNQ |
Cleanup commands
| Command | Description |
|---|---|
mc-to-synq cleanup sql-tests |
Delete migrated SQL tests (by ID prefix) |
mc-to-synq cleanup monitors |
Delete OOTB monitors (by name prefix) |
All cleanup commands support --dry-run and require confirmation before deleting.
Utility commands
| Command | Description |
|---|---|
mc-to-synq init |
Generate an annotated config file |
mc-to-synq status |
Test MC and SYNQ connections |
Configuration
All settings live in a single YAML file (mc-to-synq.yaml). Key sections:
Filters
Controls which MC monitors are selected for migration. The entity prefix filter is the primary mechanism -- a monitor is included if any of its registered entities match a prefix. Text patterns are a fallback for monitors with missing entity metadata.
filters:
entity_prefixes:
- "mydb:analytics."
- "mydb:bizviews."
text_patterns:
- "analytics"
- "bizviews"
OOTB monitor generation
Timestamp column resolution uses a priority list -- the first match per entity wins. Business keys for duplicate detection are resolved from PK and unique constraints.
ootb:
timestamp_columns:
- "DSS_LOAD_DATE"
- "LOAD_DATE"
- "MODIFIED_AT"
- "UPDATED_AT"
- "CREATED_AT"
monitor_prefix: "bv_"
The monitor_prefix is used for both naming and cleanup. All monitors created by mc-to-synq are named bv_freshness_*, bv_volume_*, bv_duplicates_*, making bulk teardown deterministic.
Network
If your environment uses an SSL-intercepting proxy, disable certificate verification:
network:
verify_ssl: false
If api.synq.io does not resolve on your DNS, use the alternative endpoint:
synq:
base_url: "https://developer.synq.io"
oauth_url: "https://developer.synq.io/oauth2/token"
See mc_to_synq/example.yaml in the source repository for the full annotated reference, or run mc-to-synq init to copy it into your project.
How it works
SQL test conversion
MC SQL monitors are converted to SYNQ SQL Tests using these rules:
| MC pattern | SYNQ handling |
|---|---|
SELECT * ... WHERE <violation> |
Passed through as-is (0 rows = pass) |
SELECT ... HAVING COUNT(*) > 1 |
Passed through (HAVING already filters to violations) |
SELECT ... WHERE NOT IN/EXISTS |
Passed through (already violation-oriented) |
SELECT COUNT(*) FROM ... |
Wrapped in outer query that returns rows only when count != 0 |
| CTE with WHERE on final SELECT | Passed through |
| CTE without WHERE on final SELECT | Flagged for manual review |
Jinja template variables ({{ }}) |
Skipped (requires manual rewrite) |
| Disabled in MC | Skipped |
Monitor type mapping
| MC type | SYNQ target | Notes |
|---|---|---|
| CUSTOM_SQL, CUSTOM_RULE | custom_numeric | Primary migration path |
| VALIDATION | custom_numeric | No native equivalent |
| METRIC | custom_numeric | Verify metric_aggregation |
| COMPARISON | custom_numeric | Manual review required |
| STATS | field_stats | Verify field list |
| FRESHNESS | freshness | Direct mapping |
| VOLUME | volume | Direct mapping |
| SCHEMA | (excluded) | Not migrated |
Idempotent operations
SQL tests use stable IDs derived from the MC rule name (prefixed with mc_migrated_). Re-running the deployment upserts rather than duplicates. OOTB monitors check for existing monitors by name before creating, so repeated runs skip already-deployed monitors.
Known limitations
- SYNQ wraps user SQL in an outer
SELECT, so CTEs and complex queries must use inline subqueries with HAVING-based violation filtering. This is a SYNQ platform constraint, not a tool limitation. - gRPC-based SYNQ services fail behind corporate proxies that strip HTTP/2 ALPN negotiation. mc-to-synq uses REST-only API paths exclusively.
- MC's GraphQL schema evolves without versioning. mc-to-synq introspects at runtime and falls back gracefully, but new schema changes may require updates.
- Monitors-as-code YAML export generates placeholder
monitored_idvalues that must be updated from the SYNQ UI before deploying viasynq-monitors apply.
Project structure
mc-to-synq/
pyproject.toml
mc_to_synq/
cli.py # Typer CLI entry point
config.py # YAML config loader (Pydantic-validated)
example.yaml # Annotated config reference (bundled with the package)
auth/
monte_carlo.py # MC GraphQL client
synq.py # SYNQ OAuth2 client
extract/
monitors.py # MC monitor extraction + schema introspection
filters.py # Config-driven entity filtering
migrate/
sql_tests.py # MC SQL -> SYNQ SQL Tests
ootb_monitors.py # Freshness/volume/duplicate generation
yaml_export.py # Monitors-as-code YAML output
deploy/
sql_tests.py # BatchUpsertSqlTests
custom_monitors.py # BatchCreateMonitor
cleanup.py # Prefix-based bulk delete
reporting/
__init__.py # JSON report generation
tests/
test_config.py
test_filters.py
test_sql_tests.py
test_classification.py
Development
git clone https://github.com/RyanSchlenz/mc-to-synq.git
cd mc-to-synq
pip install -e ".[dev]"
pytest
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mc_to_synq-0.1.0.tar.gz.
File metadata
- Download URL: mc_to_synq-0.1.0.tar.gz
- Upload date:
- Size: 38.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
980f121071fbcce61011dbf2fd73cdcaa18c990c67c1e8c95b97c0121034c617
|
|
| MD5 |
7b805939e9755a7fa90fdb6c30850bc6
|
|
| BLAKE2b-256 |
6247e91e5f71a1660e7ee571081c908f31d85abf60794f947a7cd6b365365f9e
|
File details
Details for the file mc_to_synq-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mc_to_synq-0.1.0-py3-none-any.whl
- Upload date:
- Size: 39.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
517a3aebc44c76c74c3dda2c3afa3432bf0dba615bf878068f0cbb12528239e4
|
|
| MD5 |
fc60d2d96fea397bd80f028ae451aafa
|
|
| BLAKE2b-256 |
26746d833e151c6959d05081b521de39a82b03ec2584751cb38a96db7247ad74
|