opencode-skills-collection 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-skills/.antigravity-install-manifest.json +6 -1
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/manage-skills/SKILL.md +187 -0
- package/bundled-skills/monte-carlo-monitor-creation/SKILL.md +222 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/comparison-monitor.md +426 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/custom-sql-monitor.md +207 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/metric-monitor.md +292 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/table-monitor.md +231 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/validation-monitor.md +404 -0
- package/bundled-skills/monte-carlo-prevent/SKILL.md +252 -0
- package/bundled-skills/monte-carlo-prevent/references/TROUBLESHOOTING.md +23 -0
- package/bundled-skills/monte-carlo-prevent/references/parameters.md +32 -0
- package/bundled-skills/monte-carlo-prevent/references/workflows.md +478 -0
- package/bundled-skills/monte-carlo-push-ingestion/SKILL.md +363 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/anomaly-detection.md +87 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/custom-lineage.md +203 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/direct-http-api.md +207 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/prerequisites.md +150 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/push-lineage.md +160 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/push-metadata.md +158 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/push-query-logs.md +219 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/validation.md +257 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/sample_verify.py +357 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_lineage.py +70 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_metadata.py +65 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_query_logs.py +70 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_lineage.py +214 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_metadata.py +160 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_query_logs.py +164 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_lineage.py +198 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_metadata.py +193 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_query_logs.py +207 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_metadata.py +71 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_query_logs.py +64 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_metadata.py +253 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_query_logs.py +149 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_metadata.py +190 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_query_logs.py +208 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_lineage.py +83 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_metadata.py +77 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_query_logs.py +83 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_lineage.py +240 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_metadata.py +212 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_query_logs.py +204 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_lineage.py +192 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_metadata.py +178 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_query_logs.py +200 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_lineage.py +119 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_metadata.py +119 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_query_logs.py +117 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_lineage.py +265 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_metadata.py +313 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_query_logs.py +284 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_lineage.py +309 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_metadata.py +245 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_query_logs.py +255 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_lineage.py +78 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_metadata.py +80 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_query_logs.py +88 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_lineage.py +235 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_metadata.py +219 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_query_logs.py +239 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_lineage.py +178 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_metadata.py +178 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_query_logs.py +196 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_lineage.py +154 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_metadata.py +137 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_query_logs.py +137 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_lineage.py +349 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_metadata.py +329 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_query_logs.py +254 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_lineage.py +307 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_metadata.py +228 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_query_logs.py +248 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/test_template_sdk_usage.py +340 -0
- package/bundled-skills/monte-carlo-validation-notebook/SKILL.md +685 -0
- package/bundled-skills/monte-carlo-validation-notebook/scripts/generate_notebook_url.py +141 -0
- package/bundled-skills/monte-carlo-validation-notebook/scripts/resolve_dbt_schema.py +161 -0
- package/package.json +1 -1
- package/skills_index.json +503 -61
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Pushing Query Logs
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Query logs let Monte Carlo build table usage history, populate query lineage, and surface
|
|
6
|
+
query-level insights in the catalog. Push them via `POST /ingest/v1/querylogs`.
|
|
7
|
+
|
|
8
|
+
**Important timing note**: MC processes pushed query logs asynchronously. Logs pushed now
|
|
9
|
+
may not be visible in `getAggregatedQueries` for **at least 15-20 minutes**. This is expected
|
|
10
|
+
behavior, not a bug.
|
|
11
|
+
|
|
12
|
+
**Expiration**: Pushed query logs expire on the same schedule as pulled query logs.
|
|
13
|
+
|
|
14
|
+
**Batching**: For large query log sets, split events into batches. The compressed request body
|
|
15
|
+
must not exceed **1MB** (Kinesis limit). A conservative default is 250 entries per batch.
|
|
16
|
+
|
|
17
|
+
## pycarlo model
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from pycarlo.features.ingestion import IngestionService, QueryLogEntry
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`QueryLogEntry` required fields:
|
|
24
|
+
- `start_time` (`datetime`) — when the query started
|
|
25
|
+
- `end_time` (`datetime`) — when the query finished (**required**, easy to miss)
|
|
26
|
+
- `query_text` (`str`) — the SQL statement
|
|
27
|
+
|
|
28
|
+
Optional fields:
|
|
29
|
+
- `query_id` (`str`) — warehouse-assigned query ID
|
|
30
|
+
- `user` (`str`) — user/email who ran the query
|
|
31
|
+
- `returned_rows` (`int`) — rows returned to the client
|
|
32
|
+
- `default_database` (`str`) — default database context
|
|
33
|
+
|
|
34
|
+
## Basic example
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from datetime import datetime, timezone
|
|
38
|
+
|
|
39
|
+
entries = [
|
|
40
|
+
QueryLogEntry(
|
|
41
|
+
start_time=datetime(2024, 3, 1, 10, 0, 0, tzinfo=timezone.utc),
|
|
42
|
+
end_time=datetime(2024, 3, 1, 10, 0, 5, tzinfo=timezone.utc),
|
|
43
|
+
query_text="SELECT * FROM analytics.public.orders WHERE status = 'pending'",
|
|
44
|
+
query_id="query-abc-123",
|
|
45
|
+
user="analyst@company.com",
|
|
46
|
+
returned_rows=847,
|
|
47
|
+
),
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
result = service.send_query_logs(
|
|
51
|
+
resource_uuid="<your-resource-uuid>",
|
|
52
|
+
log_type="snowflake", # ← warehouse-specific! see table below
|
|
53
|
+
entries=entries,
|
|
54
|
+
)
|
|
55
|
+
invocation_id = service.extract_invocation_id(result)
|
|
56
|
+
print("invocation_id:", invocation_id)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## log_type per warehouse
|
|
60
|
+
|
|
61
|
+
**Important**: the query-log endpoint uses `log_type`, not `resource_type`. This is the only
|
|
62
|
+
push endpoint where the field name differs from metadata/lineage. The `log_type` value must
|
|
63
|
+
match what the MC normalizer expects for your warehouse. Using the wrong value causes:
|
|
64
|
+
`ValueError: Unsupported ingest query-log log_type: <value>`
|
|
65
|
+
|
|
66
|
+
| Warehouse | log_type |
|
|
67
|
+
|---|---|
|
|
68
|
+
| Snowflake | `"snowflake"` |
|
|
69
|
+
| BigQuery | `"bigquery"` |
|
|
70
|
+
| Databricks | `"databricks"` |
|
|
71
|
+
| Redshift | `"redshift"` |
|
|
72
|
+
| Hive (EMR/S3) | `"hive-s3"` |
|
|
73
|
+
| Athena | `"athena"` |
|
|
74
|
+
| Teradata | `"teradata"` |
|
|
75
|
+
| ClickHouse | `"clickhouse"` |
|
|
76
|
+
| Databricks (SQL Warehouse) | `"databricks-metastore-sql-warehouse"` |
|
|
77
|
+
| S3 | `"s3"` |
|
|
78
|
+
| Presto (S3) | `"presto-s3"` |
|
|
79
|
+
|
|
80
|
+
## Warehouse-specific fields
|
|
81
|
+
|
|
82
|
+
Some warehouses support extra fields beyond the base `QueryLogEntry`. Pass them as keyword
|
|
83
|
+
arguments — the normalizer knows which fields are valid per warehouse.
|
|
84
|
+
|
|
85
|
+
**Snowflake extras:**
|
|
86
|
+
```python
|
|
87
|
+
QueryLogEntry(
|
|
88
|
+
...
|
|
89
|
+
bytes_scanned=1024000,
|
|
90
|
+
warehouse_name="COMPUTE_WH",
|
|
91
|
+
warehouse_size="X-Small",
|
|
92
|
+
role_name="ANALYST",
|
|
93
|
+
query_tag="reporting",
|
|
94
|
+
execution_status="SUCCESS",
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**BigQuery extras:**
|
|
99
|
+
```python
|
|
100
|
+
QueryLogEntry(
|
|
101
|
+
...
|
|
102
|
+
total_bytes_billed=10485760,
|
|
103
|
+
statement_type="SELECT",
|
|
104
|
+
job_type="QUERY",
|
|
105
|
+
default_dataset="analytics.public",
|
|
106
|
+
)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Athena extras:**
|
|
110
|
+
```python
|
|
111
|
+
QueryLogEntry(
|
|
112
|
+
...
|
|
113
|
+
bytes_scanned=2048000,
|
|
114
|
+
catalog="AwsDataCatalog",
|
|
115
|
+
database="analytics",
|
|
116
|
+
output_location="s3://my-bucket/results/",
|
|
117
|
+
state="SUCCEEDED",
|
|
118
|
+
)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Collecting query logs per warehouse
|
|
122
|
+
|
|
123
|
+
### Snowflake
|
|
124
|
+
```sql
|
|
125
|
+
SELECT
|
|
126
|
+
query_id,
|
|
127
|
+
query_text,
|
|
128
|
+
start_time,
|
|
129
|
+
end_time,
|
|
130
|
+
user_name,
|
|
131
|
+
database_name,
|
|
132
|
+
warehouse_name,
|
|
133
|
+
bytes_scanned,
|
|
134
|
+
rows_produced AS returned_rows,
|
|
135
|
+
execution_status
|
|
136
|
+
FROM snowflake.account_usage.query_history
|
|
137
|
+
WHERE start_time >= DATEADD(hour, -24, CURRENT_TIMESTAMP())
|
|
138
|
+
AND execution_status = 'SUCCESS'
|
|
139
|
+
ORDER BY start_time
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Note: `ACCOUNT_USAGE` views have up to 45 minutes of latency. Don't collect the last hour.
|
|
143
|
+
|
|
144
|
+
### BigQuery
|
|
145
|
+
```python
|
|
146
|
+
from google.cloud import bigquery
|
|
147
|
+
client = bigquery.Client(project=project_id)
|
|
148
|
+
jobs = client.list_jobs(all_users=True, min_creation_time=start_dt, max_creation_time=end_dt)
|
|
149
|
+
for job in jobs:
|
|
150
|
+
if hasattr(job, 'query') and job.query:
|
|
151
|
+
# job.job_id, job.query, job.created, job.ended, job.user_email
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Databricks
|
|
155
|
+
```sql
|
|
156
|
+
SELECT
|
|
157
|
+
statement_id AS query_id,
|
|
158
|
+
statement_text AS query_text,
|
|
159
|
+
start_time,
|
|
160
|
+
end_time,
|
|
161
|
+
executed_by AS user,
|
|
162
|
+
produced_rows AS returned_rows
|
|
163
|
+
FROM system.query.history
|
|
164
|
+
WHERE start_time >= DATEADD(HOUR, -24, NOW())
|
|
165
|
+
AND status = 'FINISHED'
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Redshift (modern clusters)
|
|
169
|
+
```sql
|
|
170
|
+
SELECT
|
|
171
|
+
query_id,
|
|
172
|
+
query_text, -- may need text assembly from SYS_QUERYTEXT for long queries
|
|
173
|
+
start_time,
|
|
174
|
+
end_time,
|
|
175
|
+
user_id,
|
|
176
|
+
status
|
|
177
|
+
FROM sys_query_history
|
|
178
|
+
WHERE start_time >= DATEADD(hour, -24, GETDATE())
|
|
179
|
+
AND status = 'success'
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
For long queries (text > 4000 chars), assemble from `SYS_QUERYTEXT`:
|
|
183
|
+
```sql
|
|
184
|
+
SELECT query_id, LISTAGG(text, '') WITHIN GROUP (ORDER BY sequence) AS full_text
|
|
185
|
+
FROM sys_querytext
|
|
186
|
+
WHERE query_id = <id>
|
|
187
|
+
GROUP BY query_id
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Hive
|
|
191
|
+
Parse the HiveServer2 log file (default: `/tmp/root/hive.log`) for lines matching:
|
|
192
|
+
```
|
|
193
|
+
(Executing|Starting) command\(queryId=(\S*)\): (?P<command>.*)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Output manifest (include invocation_id)
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
manifest = {
|
|
200
|
+
"resource_uuid": resource_uuid,
|
|
201
|
+
"invocation_id": service.extract_invocation_id(result), # ← save this
|
|
202
|
+
"collected_at": datetime.now(tz=timezone.utc).isoformat(),
|
|
203
|
+
"entry_count": len(entries),
|
|
204
|
+
"window_start": min(e.start_time for e in entries).isoformat(),
|
|
205
|
+
"window_end": max(e.end_time for e in entries).isoformat(),
|
|
206
|
+
"queries": [
|
|
207
|
+
{
|
|
208
|
+
"query_id": e.query_id,
|
|
209
|
+
"start_time": e.start_time.isoformat(),
|
|
210
|
+
"end_time": e.end_time.isoformat(),
|
|
211
|
+
"returned_rows": e.returned_rows,
|
|
212
|
+
"query": e.query_text[:200], # truncate for readability
|
|
213
|
+
}
|
|
214
|
+
for e in entries
|
|
215
|
+
],
|
|
216
|
+
}
|
|
217
|
+
with open("query_logs_output.json", "w") as f:
|
|
218
|
+
json.dump(manifest, f, indent=2)
|
|
219
|
+
```
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Validating Pushed Data
|
|
2
|
+
|
|
3
|
+
All verification queries use the **GraphQL API key** at `https://api.getmontecarlo.com/graphql`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Resolve a table's MCON and fullTableId
|
|
8
|
+
|
|
9
|
+
Before running most queries you need either the `mcon` or `fullTableId`.
|
|
10
|
+
|
|
11
|
+
`fullTableId` format: `<database>:<schema>.<table>` — e.g. `analytics:public.orders`
|
|
12
|
+
|
|
13
|
+
```graphql
|
|
14
|
+
query GetTable($fullTableId: String!, $dwId: UUID!) {
|
|
15
|
+
getTable(fullTableId: $fullTableId, dwId: $dwId) {
|
|
16
|
+
mcon
|
|
17
|
+
fullTableId
|
|
18
|
+
displayName
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Variables:
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"fullTableId": "analytics:public.orders",
|
|
27
|
+
"dwId": "<warehouse-uuid>"
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Verify metadata (schema + columns)
|
|
34
|
+
|
|
35
|
+
```graphql
|
|
36
|
+
query GetTableMetadata($mcon: String!) {
|
|
37
|
+
getTable(mcon: $mcon) {
|
|
38
|
+
mcon
|
|
39
|
+
fullTableId
|
|
40
|
+
versions {
|
|
41
|
+
edges {
|
|
42
|
+
node {
|
|
43
|
+
fields {
|
|
44
|
+
name
|
|
45
|
+
fieldType
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Check that the fields list matches your pushed schema.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Verify volume and freshness metrics
|
|
59
|
+
|
|
60
|
+
Use `getMetricsV4` to fetch row counts and last-modified timestamps:
|
|
61
|
+
|
|
62
|
+
```graphql
|
|
63
|
+
query GetMetrics(
|
|
64
|
+
$mcon: String!
|
|
65
|
+
$metricName: String!
|
|
66
|
+
$startTime: DateTime!
|
|
67
|
+
$endTime: DateTime!
|
|
68
|
+
) {
|
|
69
|
+
getMetricsV4(
|
|
70
|
+
dwId: null
|
|
71
|
+
mcon: $mcon
|
|
72
|
+
metricName: $metricName
|
|
73
|
+
startTime: $startTime
|
|
74
|
+
endTime: $endTime
|
|
75
|
+
) {
|
|
76
|
+
metricsJson
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Variables (row count):
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"mcon": "<table-mcon>",
|
|
85
|
+
"metricName": "total_row_count",
|
|
86
|
+
"startTime": "2024-03-01T00:00:00Z",
|
|
87
|
+
"endTime": "2024-03-02T00:00:00Z"
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`metricsJson` is a JSON string. Parse it and look for `value` and `measurementTimestamp`
|
|
92
|
+
(camelCase) in each data point.
|
|
93
|
+
|
|
94
|
+
Other useful metric names:
|
|
95
|
+
- `"total_row_count"` — row count
|
|
96
|
+
- `"total_byte_count"` — byte size
|
|
97
|
+
- `"total_row_count_last_changed_on"` — Unix epoch float of when the row count last changed
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Verify table lineage
|
|
102
|
+
|
|
103
|
+
```graphql
|
|
104
|
+
query GetTableLineage($mcon: String!) {
|
|
105
|
+
getTableLineage(mcon: $mcon, direction: "upstream", hops: 1) {
|
|
106
|
+
connectedNodes {
|
|
107
|
+
mcon
|
|
108
|
+
displayName
|
|
109
|
+
objectType
|
|
110
|
+
}
|
|
111
|
+
flattenedEdges {
|
|
112
|
+
directlyConnectedMcons
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Check that your expected source tables appear in `connectedNodes` or
|
|
119
|
+
`flattenedEdges[].directlyConnectedMcons`.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Verify column lineage
|
|
124
|
+
|
|
125
|
+
```graphql
|
|
126
|
+
query GetColumnLineage($mcon: String!, $column: String!) {
|
|
127
|
+
getDerivedTablesPartialLineage(mcon: $mcon, column: $column, pageSize: 1000) {
|
|
128
|
+
destinations {
|
|
129
|
+
table { mcon displayName }
|
|
130
|
+
columns { columnName }
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Variables: `mcon` = source table MCON, `column` = source column name.
|
|
137
|
+
|
|
138
|
+
Check that each destination table and column appears in the response.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Verify query logs
|
|
143
|
+
|
|
144
|
+
```graphql
|
|
145
|
+
query GetAggregatedQueries(
|
|
146
|
+
$mcon: String!
|
|
147
|
+
$queryType: String!
|
|
148
|
+
$startTime: DateTime!
|
|
149
|
+
$endTime: DateTime!
|
|
150
|
+
$first: Int
|
|
151
|
+
$after: String
|
|
152
|
+
) {
|
|
153
|
+
getAggregatedQueries(
|
|
154
|
+
mcon: $mcon
|
|
155
|
+
queryType: $queryType
|
|
156
|
+
startTime: $startTime
|
|
157
|
+
endTime: $endTime
|
|
158
|
+
first: $first
|
|
159
|
+
after: $after
|
|
160
|
+
) {
|
|
161
|
+
edges { node { queryHash queryCount lastSeen } }
|
|
162
|
+
pageInfo { hasNextPage endCursor }
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Variables:
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"mcon": "<table-mcon>",
|
|
171
|
+
"queryType": "read",
|
|
172
|
+
"startTime": "2024-03-01T00:00:00Z",
|
|
173
|
+
"endTime": "2024-03-02T00:00:00Z",
|
|
174
|
+
"first": 100
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Remember**: query logs take up to 1 hour to process after push. If you see 0 results
|
|
179
|
+
immediately after pushing, wait and try again.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Check detector thresholds (anomaly detection status)
|
|
184
|
+
|
|
185
|
+
```graphql
|
|
186
|
+
query GetDetectorStatus($mcon: String!) {
|
|
187
|
+
getTable(mcon: $mcon) {
|
|
188
|
+
thresholds {
|
|
189
|
+
freshness {
|
|
190
|
+
lower { value }
|
|
191
|
+
upper { value }
|
|
192
|
+
status
|
|
193
|
+
}
|
|
194
|
+
size {
|
|
195
|
+
lower { value }
|
|
196
|
+
upper { value }
|
|
197
|
+
status
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
`status` will be `"no data"` or `"inactive"` on a newly-pushed table. Detectors need
|
|
205
|
+
historical data to train — see `references/anomaly-detection.md` for requirements.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Table management operations
|
|
210
|
+
|
|
211
|
+
### Delete push-ingested tables
|
|
212
|
+
|
|
213
|
+
Only works on push-ingested tables — pull-collected tables are excluded by default.
|
|
214
|
+
|
|
215
|
+
```graphql
|
|
216
|
+
mutation DeletePushTables($mcons: [String!]!) {
|
|
217
|
+
deletePushIngestedTables(mcons: $mcons) {
|
|
218
|
+
success
|
|
219
|
+
deletedCount
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Variables:
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"mcons": ["<mcon-1>", "<mcon-2>"]
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Resolve MCONs first with `getTable(fullTableId: ..., dwId: ...)`.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Python helper
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
import requests, json
|
|
239
|
+
|
|
240
|
+
GRAPHQL_URL = "https://api.getmontecarlo.com/graphql"
|
|
241
|
+
|
|
242
|
+
def graphql(query: str, variables: dict, key_id: str, key_token: str) -> dict:
|
|
243
|
+
resp = requests.post(
|
|
244
|
+
GRAPHQL_URL,
|
|
245
|
+
json={"query": query, "variables": variables},
|
|
246
|
+
headers={
|
|
247
|
+
"x-mcd-id": key_id,
|
|
248
|
+
"x-mcd-token": key_token,
|
|
249
|
+
"Content-Type": "application/json",
|
|
250
|
+
},
|
|
251
|
+
)
|
|
252
|
+
resp.raise_for_status()
|
|
253
|
+
data = resp.json()
|
|
254
|
+
if "errors" in data:
|
|
255
|
+
raise RuntimeError(json.dumps(data["errors"], indent=2))
|
|
256
|
+
return data["data"]
|
|
257
|
+
```
|