{"flow":{"id":8,"summary":"Monitor database & emit metrics to datadog","versions":[11,28],"created_by":"admin","created_at":"2022-07-24T23:52:53.247Z","votes":0,"approved":false,"apps":["postgressql","datadog","slack"],"value":{"modules":[{"value":{"path":"u/Ross/deno-datadog-flow/step-0","type":"rawscript","content":"import * as wmill from \"https://deno.land/x/windmill@v1.27.2/mod.ts\";\nimport { Client } from \"https://deno.land/x/postgres@v0.16.1/mod.ts\";\n\nconst calculateVariancePercentage = (data) => {\n  const meanValue = data.reduce((sum, element) => sum + element, 0) /\n    data.length;\n  const sumOfDeviations = data.reduce(\n    (sod, element) => Math.pow(element - meanValue, 2),\n    0,\n  );\n  const variance = sumOfDeviations / (data.length - 1);\n  return variance / meanValue * 100;\n};\n\nexport async function main(\n  threshold: number,\n  db: wmill.Resource<\"postgresql\">,\n) {\n  let variance_before = await wmill.getInternalState();\n  db.database = db.dbname;\n  db.hostname = db.host;\n  const client = new Client(db);\n  await client.connect();\n\n  for (let index = 0; index < 50; index++) {\n    const add_update_lead_db_query: string =\n      `INSERT INTO temp_example_table(stat) VALUES (${rdGenerator()});`;\n    await client.queryObject(\n      add_update_lead_db_query,\n    );\n  }\n\n  const select_distinct_query = \"SELECT stat FROM temp_example_table LIMIT 50\";\n\n  let returned_query = await client.queryObject(select_distinct_query);\n  let rows = returned_query.rows;\n  let data_list: Array<number> = [];\n  for (let i in rows) {\n    data_list.push(+rows[i][\"stat\"]);\n  }\n  const variance_after = await wmill.setInternalState(\n    calculateVariancePercentage(data_list),\n  );\n\n  if (variance_before < threshold && variance_after > threshold) {\n    const error_message =\n      `@eng team: The postgres database has exceeded the threshold ${threshold}, it is currently at ${variance_after}: see the following doc https://example.com/doc for information on how to resolve the issue`;\n    return {\n      data_error: true,\n      data_list: data_list,\n      error_message: error_message,\n    };\n  }\n\n  return { data_error: false, data_list: [], error_message: \"\" };\n}\n","language":"deno"},"input_transform":{"db":{"type":"static","value":null},"threshold":{"type":"static","value":""}}},{"value":{"type":"rawscript","content":"import * as wmill from \"https://deno.land/x/windmill@v1.18.0/mod.ts\";\nimport { WebClient } from \"https://deno.land/x/slack_web_api@1.0.3/mod.ts\";\n\nexport async function main(\n  flag: boolean,\n  channel: string,\n  text: string,\n  username: string,\n) {\n    let message = '';\n\n  if (flag) {\n\n    const web = new WebClient(await wmill.getVariable(\"g/all/slack_token\"));\n    if (channel == \"\") {\n      channel = null;\n    }\n    if (username == \"\") {\n      username = null;\n    }\n    if (\n      (channel == null && username == null) ||\n      channel != null && username != null\n    ) {\n      throw \"one and only one of channel or user need to be set\";\n    }\n    if (username != null) {\n      channel = `@${username}`;\n    }\n\n    await web.chat.postMessage({\n      channel: channel,\n      text: text,\n      username: username,\n    });\n    message = `Data error posted in ${channel}: ${text}`;\n\n  }\n\n  return { message: message };\n}\n","language":"deno"},"input_transform":{"flag":{"expr":"import { previous_result, flow_input, step, variable, resource, params } from 'windmill@1'\n\nprevious_result.data_error","type":"javascript"},"text":{"expr":"import { previous_result, flow_input, step, variable, resource, params } from 'windmill@1'\n\nprevious_result.error_message","type":"javascript"},"channel":{"type":"static","value":""},"username":{"type":"static","value":""}}},{"value":{"type":"rawscript","content":"import * as wmill from \"https://deno.land/x/windmill@v1.18.0/mod.ts\";\nimport ApiClient from \"https://deno.land/x/datadog_api/client.ts\";\nimport v1MetricsApi from \"https://deno.land/x/datadog_api/v1/metrics.ts\";\n\nexport async function main(\n  dd_auth: wmill.Resource<\"datadog\">,\n  data_error: boolean,\n  datapoints: object,\n  metric_name: string,\n) {\n  let message = \"\";\n  if (data_error == true) {\n    const datadog = new ApiClient(dd_auth);\n    const metricsApi = new v1MetricsApi(datadog);\n\n    for (let index in datapoints) {\n      const metricsStatus = await metricsApi.submit([{\n        metric_name: metric_name,\n        points: [{ value: datapoints[index] }],\n        interval: 10,\n        metric_type: \"gauge\",\n      }]);\n    }\n    message = \"Data emitted to datadog\";\n  }\n  return { message: message };\n}\n","language":"deno"},"input_transform":{"dd_auth":{"type":"static","value":"$res:undefined"},"data_error":{"expr":"import { previous_result, flow_input, step, variable, resource, params } from 'windmill@2'\n\nprevious_result.step(0).data_error","type":"javascript"},"datapoints":{"expr":"import { previous_result, flow_input, step, variable, resource, params } from 'windmill@2'\n\nprevious_result.step(0).data_list","type":"javascript"},"metric_name":{"type":"static","value":""}}}]},"schema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","required":[],"properties":{}},"description":"Monitor database infrastructure metrics by running an SQL query, alert a slack channel on the state of the database if a particular metric exceeds a threshold value and then emits metrics Datadog for recording and monitoring.","recording":null,"vcreated_at":"2022-08-03T21:33:19.427Z","vcreated_by":"rossmccrann","comments":[]}}