All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.snowflake.client.core.Incident Maven / Gradle / Ivy

There is a newer version: 3.23.1
Show newest version
/*
 * Copyright (c) 2019 Snowflake Computing Inc. All rights reserved.
 */
package net.snowflake.client.core;

import static net.snowflake.client.jdbc.SnowflakeUtil.systemGetProperty;
import static net.snowflake.client.util.SFTimestamp.getUTCNow;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Preconditions;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
import net.snowflake.client.jdbc.SnowflakeDriver;
import net.snowflake.client.jdbc.SnowflakeSQLException;
import net.snowflake.client.log.SFLogger;
import net.snowflake.client.log.SFLoggerFactory;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.tika.utils.ExceptionUtils;

public class Incident extends Event {
  private static final SFLogger logger = SFLoggerFactory.getLogger(Incident.class);
  private static final String SF_PATH_CREATE_INCIDENT_V2 = "/incidents/v2/create-incident";

  // Incident Fields
  final String serverUrl;
  final String sessionToken;
  final String driverName = "jdbc";
  final String driverVersion = SnowflakeDriver.implementVersion;
  final String signature;
  final String errorMessage;
  final String errorStackTrace;
  final String osName;
  final String osVersion;
  final String jobId;
  final String requestId;
  final String timestamp = getUTCNow() + ".000";
  final String uuid = UUID.randomUUID().toString();
  HttpClientSettingsKey ocspAndProxyKey = null;

  /**
   * Submit an exception to GS from a Throwable, this is the only constructor that should be used to
   * report incidents
   *
   * @param exc a Throwable we want to report
   * @param jobId job id String
   * @param requestId request id string
   */
  public Incident(SFSession session, Throwable exc, String jobId, String requestId) {
    this(
        session,
        jobId,
        requestId,
        exc.getMessage(),
        ExceptionUtils.getStackTrace(exc),
        String.valueOf(exc.getStackTrace()[0]));
  }

  /**
   * Submit an exception to GS from a Throwable, this is the only constructor that should be used to
   * report incidents
   *
   * @param serverUrl GS's url
   * @param sessionToken GS's session token
   * @param key OCSP mode and proxy settings
   * @param exc an Throwable we want to report
   * @param jobId job id String
   * @param requestId request id string
   */
  public Incident(
      String serverUrl,
      String sessionToken,
      HttpClientSettingsKey key,
      Throwable exc,
      String jobId,
      String requestId) {
    this(
        serverUrl,
        sessionToken,
        jobId,
        requestId,
        exc.getMessage(),
        ExceptionUtils.getStackTrace(exc),
        String.valueOf(exc.getStackTrace()[0]));
    this.ocspAndProxyKey = key;
  }

  /**
   * A constructor for a V2 client incident with all fields explicitly given
   *
   * @param session current session's SFSession object
   * @param jobId offending job id
   * @param requestId offending request id
   * @param errorMessage error message to be reported
   * @param errorStackTrace stack trace to be reported
   * @param raiser string representation of top of stack trace
   */
  Incident(
      SFSession session,
      String jobId,
      String requestId,
      String errorMessage,
      String errorStackTrace,
      String raiser) {
    this(
        session.getServerUrl(),
        session.getSessionToken(),
        jobId,
        requestId,
        errorMessage,
        errorStackTrace,
        raiser);
    try {
      this.ocspAndProxyKey = session.getHttpClientKey();
    } catch (SnowflakeSQLException e) {
      // do nothing
    }
  }

  /**
   * A constructor for a V2 client incident with all fields explicitly given
   *
   * @param serverUrl GS server's URL
   * @param sessionToken current session token
   * @param jobId offending job id
   * @param requestId offending request id
   * @param errorMessage error message of exception to be reported
   * @param errorStackTrace stack trace to be reported
   * @param raiser String representation of top of the stack
   */
  Incident(
      String serverUrl,
      String sessionToken,
      String jobId,
      String requestId,
      String errorMessage,
      String errorStackTrace,
      String raiser) {
    super(Event.EventType.INCIDENT, errorMessage);
    this.serverUrl = serverUrl;
    this.sessionToken = sessionToken;
    this.jobId = jobId;
    this.requestId = requestId;
    this.signature = generateSignature(errorMessage, raiser);
    this.errorMessage = errorMessage;
    this.errorStackTrace = errorStackTrace;
    // Generated fields
    this.osName = systemGetProperty("os.name");
    this.osVersion = systemGetProperty("os.version");
  }

  /**
   * Generate Signature of the incident automatically, signature should not be written manually
   *
   * @param errorMessage error message of exception to be reported
   * @param raiser String representation of top of stack
   * @return String of signature created
   */
  private static String generateSignature(String errorMessage, String raiser) {
    return errorMessage + " at " + raiser;
  }

  /** Sends incident to GS to log */
  @Override
  public void flush() {
    ObjectMapper mapper = ObjectMapperFactory.getObjectMapper();
    String dtoDump;
    URI incidentURI;
    try {
      dtoDump = mapper.writeValueAsString(new IncidentV2DTO(this));
    } catch (JsonProcessingException ex) {

      logger.error(
          "Incident registration failed, could not map "
              + "incident report to json string. Exception: {}",
          ex.getMessage());
      return;
    }

    // Sanity check...
    Preconditions.checkNotNull(dtoDump);

    try {
      URIBuilder uriBuilder = new URIBuilder(this.serverUrl);
      uriBuilder.setPath(SF_PATH_CREATE_INCIDENT_V2);
      incidentURI = uriBuilder.build();
    } catch (URISyntaxException ex) {
      logger.error(
          "Incident registration failed, " + "URI could not be built. Exception: {}",
          ex.getMessage());
      return;
    }

    HttpPost postRequest = new HttpPost(incidentURI);
    postRequest.setHeader(
        SFSession.SF_HEADER_AUTHORIZATION,
        SFSession.SF_HEADER_SNOWFLAKE_AUTHTYPE
            + " "
            + SFSession.SF_HEADER_TOKEN_TAG
            + "=\""
            + this.sessionToken
            + "\"");

    // Compress the payload.
    ByteArrayEntity input = null;
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      GZIPOutputStream gzos = new GZIPOutputStream(baos);
      byte[] bytes = dtoDump.getBytes(StandardCharsets.UTF_8);
      gzos.write(bytes);
      gzos.finish();
      input = new ByteArrayEntity(baos.toByteArray());
      input.setContentType("application/json");
    } catch (IOException exc) {
      logger.debug(
          "Incident registration failed, could not compress" + " payload. Exception: {}",
          exc.getMessage());
    }

    postRequest.setEntity(input);
    postRequest.addHeader("content-encoding", "gzip");

    try {
      String response =
          HttpUtil.executeGeneralRequest(
              postRequest,
              1000,
              ocspAndProxyKey != null
                  ? ocspAndProxyKey
                  : new HttpClientSettingsKey(OCSPMode.FAIL_OPEN));
      logger.debug("Incident registration was successful. Response: '{}'", response);
    } catch (Exception ex) {
      // No much we can do here besides complain.
      logger.error("Incident registration request failed, exception: {}", ex.getMessage());
    }
  }

  void trigger() {
    EventUtil.triggerIncident(this);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy