{ minijohn }

Monitor failing retool queries with real-time slack notifications

Feb 9, 2022 · @minijohn

A quick guide on how to get real-time alerts in slack when your retool queries are failing.

Ever thought about error monitoring for your failing queries? Me too 🙈, this is what I came up with after going down the rabbit hole:

  • 1 main JS Query acting as the router for all failing query data
  • 1 main Slack Query that sends that data to a channel

The drawback is that you need to explicitly reference the queries you want to listen to in your main JS query so their payload is available on execution as currently all queries get sandboxed with only the data that is referenced in the query for performance reasons.

tldr; You need to add all queries you want to monitor to the file.

This is how my router looks like:

var triggerQueryId = triggeredById

var triggerQuery = {
  get_users: get_users.data,
  get_vacations_for_user: get_vacations_for_user.data,
  get_user_attributes: get_user_attributes.data
}[triggerQueryId]

// meta info
var userEmail = current_user.email
var inEditorMode = retoolContext.inEditorMode
var appName = app_info.value.name
var urlParams = new URL(urlparams.href)
var appUrl = (urlParams.origin + urlParams.pathname).replace('/apps/', '/editor/')
var exactDateTime = moment().format('MM/DD/YY hh:mma')

// device info
var browserName, os
var userAgent = window.navigator.userAgent
var platform = window.navigator.platform
var macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']
var windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE']
var iosPlatforms = ['iPhone', 'iPad', 'iPod']

if(userAgent.match(/chrome|chromium|crios/i)) {
 browserName = "Chrome";
} else if(userAgent.match(/firefox|fxios/i)) {
 browserName = "Firefox";
}  else if(userAgent.match(/safari/i)) {
 browserName = "Safari";
} else if(userAgent.match(/opr\//i)) {
 browserName = "Opera";
} else if(userAgent.match(/edg/i)) {
 browserName = "Edge";
} else {
 browserName = "No browser detected";
}

if (macosPlatforms.indexOf(platform) !== -1) {
  os = 'Mac OS';
} else if (iosPlatforms.indexOf(platform) !== -1) {
  os = 'iOS';
} else if (windowsPlatforms.indexOf(platform) !== -1) {
  os = 'Windows';
} else if (/Android/.test(userAgent)) {
  os = 'Android';
} else if (!os && /Linux/.test(platform)) {
  os = 'Linux';
}

// error info
var errorMessage = triggerQuery.message
var errorPosition = triggerQuery.position
var errorSource = triggerQuery.source
var errorResourceType = triggerQuery.queryExecutionMetadata.resourceType
var errorResourceTimeMs = triggerQuery.queryExecutionMetadata.resourceTimeTakenMs

var payload = {
  userEmail: userEmail,
  appName: appName,
  appUrl: appUrl,
  errorMessage: errorMessage,
  errorSource: errorSource,
  errorResourceType: errorResourceType,
  errorPosition: errorPosition,
  errorResourceTimeMs: errorResourceTimeMs,
  exactDateTime: exactDateTime,
  browserName: browserName,
  os: os,
  triggerQuery: triggerQueryId
}

// only send notifications when in preview mode
if (inEditorMode) {
  console.log(payload)
} else {
  query_failure_slack_notification.trigger({
    additionalScope: payload,
  });
}

It constructs all the parameters we need to pass to our notification message. Most importantly

  • userEmail the currently logged in user that triggered the failing query
  • errorMessage the error message returned from the failing query
  • browserName and os information of the end user

Error notifications 

Example slack notification for a failed retool query
Example slack notification for a failed retool query

Now that you basically have all the request and meta data about your failing query you can choose where to send it to. Here, we'll be using Slack.

Retool does have a native Slack integration but it limits the payload to a simple, multi-line message.

By using a REST query we'll be able to send a message with advanced formatting to your Slack channel's Webhook URL. The query setup is simple

Retool REST query for slack webhook post request
Retool REST query for slack webhook post request

the more difficult part is creating a message template with Slack's Block Kit.

You can get the blocks layout from here