-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
216 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
DT_LOG_EXPIRATION_DAYS=14 | ||
MAX_DAYS_TO_ROLLUP=1 | ||
BQ_DATASET=development | ||
ATHENA_DB= | ||
ATHENA_TABLE= | ||
BQ_DATASET= | ||
DT_LOG_EXPIRATION_DAYS= | ||
MAX_DAYS_TO_ROLLUP= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
const log = require("lambda-log"); | ||
const { | ||
AthenaClient, | ||
StartQueryExecutionCommand, | ||
GetQueryExecutionCommand, | ||
GetQueryResultsCommand, | ||
} = require("@aws-sdk/client-athena"); | ||
|
||
// helper to start a query | ||
async function startQuery(client, QueryString, ExecutionParameters = null) { | ||
const params = { | ||
QueryString, | ||
ExecutionParameters, | ||
QueryExecutionContext: { | ||
Catalog: "AwsDataCatalog", | ||
Database: process.env.ATHENA_DB, | ||
}, | ||
OutputLocation: "s3://prx-ryan/why-does-it-not-put-results-here/", | ||
}; | ||
const command = await new StartQueryExecutionCommand(params); | ||
const response = await client.send(command); | ||
return response.QueryExecutionId; | ||
} | ||
|
||
// helper to wait for query | ||
async function waitQuery(client, QueryExecutionId) { | ||
const command = await new GetQueryExecutionCommand({ QueryExecutionId }); | ||
const response = await client.send(command); | ||
const state = response.QueryExecution.Status.State; | ||
if (state === "SUCCEEDED") { | ||
return true; | ||
} | ||
if (state === "QUEUED" || state === "RUNNING") { | ||
await new Promise((r) => { | ||
setTimeout(r, 1000); | ||
}); | ||
return waitQuery(client, QueryExecutionId); | ||
} | ||
log.error("athena query failed", { err: response }); | ||
throw new Error("query failed"); | ||
} | ||
|
||
// helper to load all pages of results | ||
async function loadResults(client, QueryExecutionId, NextToken = null) { | ||
const params = { QueryExecutionId, NextToken, MaxResults: 1000 }; | ||
const command = new GetQueryResultsCommand(params); | ||
const response = await client.send(command); | ||
const rows = response.ResultSet.ResultRows.map((r) => r.Data); | ||
if (!NextToken) { | ||
rows.shift(); // first row contains headers | ||
} | ||
if (response.NextToken) { | ||
return rows.concat( | ||
await loadResults(client, QueryExecutionId, response.NextToken), | ||
); | ||
} | ||
return rows; | ||
} | ||
|
||
/** | ||
* Run a query and wait for the result | ||
*/ | ||
exports.query = async (sql, params = null) => { | ||
const athena = new AthenaClient(); | ||
const id = await startQuery(athena, sql, params); | ||
await waitQuery(athena, id); | ||
return loadResults(athena, id); | ||
}; | ||
|
||
/** | ||
* Query path/bytes usage information from Athena | ||
*/ | ||
exports.queryUsage = async (day) => { | ||
const dayStr = day.toISOString().split("T").shift(); | ||
const removeRegion = "REGEXP_REPLACE(uri, '\\A/(use1/|usw2/)?')"; | ||
const uri = `REGEXP_REPLACE(${removeRegion}, '/[^/]+/[^/]+\\z')`; | ||
const tbl = process.env.ATHENA_TABLE; | ||
const sql = `SELECT ${uri}, SUM(bytes) FROM ${tbl} WHERE date = DATE(?) GROUP BY ${uri}`; | ||
|
||
// NOTE: for some reason, date params must be quoted | ||
return exports.query(sql, [`'${dayStr}'`]); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
describe("athena", () => { | ||
describe("queryUsage", () => { | ||
test("todo", () => { | ||
expect("todo").toEqual("todo"); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters