TreasureData에서 일정 이상의 시간이 걸리는 작업을 GAS를 사용하여 Slack에 알립니다.

배경



당사는 여러 서비스로 TreasureData를 이용하고 있어, 사용자수도 100이상으로 엔지니어로부터 데이터 사이언티스트, 비즈니스 측의 인간과 다양합니다.

임시 쿼리를 던졌을 때 TD_TIME_RANGE 의 설정을 잊어버려 리소스를 대량으로 먹어 버려 다른 쿼리에 영향을 주는 경우가 많습니다.
물론 priority를 ​​사용하여 운영하고 있지만 실제 서비스에서 사용하는 쿼리에 영향을 줄 수 있습니다.

그래서 API를 통해 일정 시간 이상 움직이는 쿼리를 검색하고 Slack에 알리는 GoogleAppsScript를 작성했습니다.
임계값 이상의 쿼리에서도 단순히 S3 등에 외부 내보내는 데 시간이 걸리고 있는 경우도 있으므로 리소스 상황(Mapper,Reducer의 수)도 함께 통지해 보았습니다.

Google Apps Script



너무 깨끗한 것은 아니지만 움직이고 있기 때문에 용서해주십시오.
이번에는 Hive 쿼리만을 대상으로 하고 있습니다.

var THRESHOLD = 1800; // しきい値30分以上
var TDAPIKEY  = '(TreasureData APIKEY)';
var WEBHOOKURL = 'https://(Slack Webhook URL)';


function postSlack(message) {
  var payload = {
    "text" : message,
    "username" : "The Machine", // "Person of Interest"が好きなので
    "channel" : "#treasuredata_alert"
  };
  var params = {
    "method" : "POST",
    "payload" : JSON.stringify(payload)
  };
  var response = UrlFetchApp.fetch(WEBHOOKURL, params);
}

function tdJobList() {
  var options = {
    "method": "GET",
    "contentType" : "application/json",
    "headers" : {
      "AUTHORIZATION" : "TD1 " + TDAPIKEY
    }
  };
  var response = UrlFetchApp.fetch('https://api.treasuredata.com/v3/job/list?status=running&from=0&to=99', options);
  return JSON.parse(response);
}

function tdJobDetail(jobid) {
  var options = {
    "method": "GET",
    "contentType" : "application/json",
    "headers" : {
      "AUTHORIZATION" : "TD1 " + TDAPIKEY
    }
  };
  var response = UrlFetchApp.fetch('https://api.treasuredata.com/v3/job/show/' + jobid, options);
  return JSON.parse(response);
}

function getCpuUsage(jobid) {
  var job = tdJobDetail(jobid);
  var logs = job.debug.stderr.split('\n');
  var cpuUsage = [];
  logs.forEach(function(line) {
    if(line.match(/^Hadoop job information for /)) {
      cpuUsage.push(line)
    }
  });
  return cpuUsage;
}

function createAlertMsg(userName, url, database, query, cpuUsage) {
  var msg =  THRESHOLD / 60 + '分以上実行されているクエリがあります! :dizzy_face: \n';
  msg += 'User: ' + userName + '\n';
  msg += 'Database: ' + database + '\n';
  msg += 'Query: ' + query.split('\n')[0] + ' .....\n';
  msg += '<' + url + '>\n';
  msg += 'Resource Usage:\n';
  msg += '```\n' + cpuUsage.join('\n') + '\n```\n';

  return msg;
}

function parseDate(str) {
  return new Date(str.replace(/-/g, "/").replace("UTC", "+00:00"));
}

function checkTdJobs() {
  var now = new Date();
  var response = tdJobList();
  var jobs = response.jobs
  jobs.forEach(function(job) {
    if (job.type !== 'hive') return;
    var startAt = parseDate(job.start_at);
    var duration = (now - startAt) / 1000;
    if (duration > THRESHOLD) {
      var cpuUsage = getCpuUsage(job.job_id);
      postSlack(createAlertMsg(job.user_name, job.url, job.database, job.query, cpuUsage));
    }
  })
}

알림 결과



이런 식으로 통지됩니다.

좋은 웹페이지 즐겨찾기