created: 2022-09-24T08:49:57.587Z

GCP の CloudPubSub/Function で処理しているログデータから、CloudLogging への直リンクを取得する

CloudLogging の機能でシンクを設定して CloudPubSub 経由で飛ばしている場合、ログを CloudFunction などで処理することになるが、Slack への通知などでそのログへの直リンクがとれると便利だったのでメモ。

URL を踏むと GCP の元々のログのページをコンソールで開くことができる。

export type LogEntry = {
  insertId: string;
  labels?: {
    execution_id: string;
  };
  logName: string;
  receiveTimestamp: string;
  severity: string;
  timestamp: string;
  trace?: string;
  resource: {
    type: string;
    labels: { [key: string]: string };
  };
  textPayload?: string;
  protoPayload?: any;
  jsonPayload?: any;
};

export const logEntryUrl = (log: LogEntry) => {
  const at = new Date(log.timestamp);
  // execution_idをカバーできる時間(cloudfunctionの実行時間は最長で1時間のため)
  const secondAround = 1000 * 60 * 60;
  const from = new Date(at.getTime() - secondAround).toISOString();
  const to = new Date(at.getTime() + secondAround).toISOString();
  const conds = [`resource.type="${log.resource.type}"`];
  if (log.labels?.execution_id) {
    conds.push(`labels.execution_id="${log.labels.execution_id}"`);
  } else {
    conds.push(`insert_id="${log.insertId}"`);
  }
  const q = querystring.escape(conds.join("\n"));
  const timeRange = "timeRange=" + querystring.escape(`${from}/${to}`);
  const cursorTimestamp = "cursorTimestamp=" + querystring.escape(`${to}`);
  const query = [q, timeRange, cursorTimestamp].join(";");
  const param = `?project=${getEnv("GCP_PROJECT_ID")}`;
  return `https://console.cloud.google.com/logs/query;query=${query}${param}`;
};