Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

telemetry(amazonq): Update /dev error classification logic #5469

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ import software.aws.toolkits.jetbrains.common.session.Intent
import software.aws.toolkits.jetbrains.services.amazonqDoc.docServiceError
import software.aws.toolkits.jetbrains.services.amazonqDoc.session.DocGenerationStreamResult
import software.aws.toolkits.jetbrains.services.amazonqDoc.session.ExportDocTaskAssistResultArchiveStreamResult
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ApiException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.CodeIterationLimitException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ContentLengthException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ExportParseException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.FEATURE_NAME
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.FeatureDevException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.FeatureDevOperation
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.MonthlyConversationLimitError
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ZipFileCorruptedException
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
import software.aws.toolkits.resources.message
Expand Down Expand Up @@ -70,8 +72,14 @@ class AmazonQCodeGenService(val proxyClient: AmazonQCodeGenerateClient, val proj
if (e is ServiceQuotaExceededException) {
throw MonthlyConversationLimitError(errMssg, operation = FeatureDevOperation.CreateConversation.toString(), desc = null, cause = e.cause)
}
throw ApiException.of(e.statusCode(), errMssg, operation = FeatureDevOperation.CreateConversation.toString(), desc = null, e.cause)
}
throw FeatureDevException(errMssg, operation = FeatureDevOperation.CreateConversation.toString(), desc = null, e.cause)
throw ServiceException(
errMssg ?: "CreateTaskAssistConversation failed",
operation = FeatureDevOperation.CreateConversation.toString(),
desc = null,
e.cause
)
} finally {
AmazonqTelemetry.startConversationInvoke(
amazonqConversationId = conversationId,
Expand Down Expand Up @@ -111,8 +119,10 @@ class AmazonQCodeGenService(val proxyClient: AmazonQCodeGenerateClient, val proj
}
throw ContentLengthException(operation = FeatureDevOperation.CreateUploadUrl.toString(), desc = null, cause = e.cause)
}

throw ApiException.of(e.statusCode(), errMssg, operation = FeatureDevOperation.CreateUploadUrl.toString(), desc = null, e.cause)
}
throw FeatureDevException(errMssg, operation = FeatureDevOperation.CreateUploadUrl.toString(), desc = null, e.cause)
throw ServiceException(errMssg ?: "CreateUploadUrl failed", operation = FeatureDevOperation.CreateUploadUrl.toString(), desc = null, e.cause)
}
}

Expand Down Expand Up @@ -156,8 +166,14 @@ class AmazonQCodeGenService(val proxyClient: AmazonQCodeGenerateClient, val proj
} else if (e is ValidationException && e.message?.contains("zipped file is corrupted") == true) {
throw ZipFileCorruptedException(operation = FeatureDevOperation.StartTaskAssistCodeGeneration.toString(), desc = null, e.cause)
}
throw ApiException.of(e.statusCode(), errMssg, operation = FeatureDevOperation.StartTaskAssistCodeGeneration.toString(), desc = null, e.cause)
}
throw FeatureDevException(errMssg, operation = FeatureDevOperation.StartTaskAssistCodeGeneration.toString(), desc = null, e.cause)
throw ServiceException(
errMssg ?: "StartTaskAssistCodeGeneration failed",
operation = FeatureDevOperation.StartTaskAssistCodeGeneration.toString(),
desc = null,
e.cause
)
}
}

Expand All @@ -180,8 +196,14 @@ class AmazonQCodeGenService(val proxyClient: AmazonQCodeGenerateClient, val proj
if (e is CodeWhispererRuntimeException) {
errMssg = e.awsErrorDetails().errorMessage()
logger.warn(e) { "GetTaskAssistCodeGeneration failed for request: ${e.requestId()}" }
throw ApiException.of(e.statusCode(), errMssg, operation = FeatureDevOperation.GetTaskAssistCodeGeneration.toString(), desc = null, e.cause)
}
throw FeatureDevException(errMssg, operation = FeatureDevOperation.GetTaskAssistCodeGeneration.toString(), desc = null, e.cause)
throw ServiceException(
errMssg ?: "GetTaskAssistCodeGeneration failed",
operation = FeatureDevOperation.GetTaskAssistCodeGeneration.toString(),
desc = null,
e.cause
)
}
}

Expand All @@ -198,7 +220,12 @@ class AmazonQCodeGenService(val proxyClient: AmazonQCodeGenerateClient, val proj
errMssg = e.awsErrorDetails().errorMessage()
logger.warn(e) { "ExportTaskAssistArchiveResult failed for request: ${e.requestId()}" }
}
throw FeatureDevException(errMssg, operation = FeatureDevOperation.ExportTaskAssistArchiveResult.toString(), desc = null, e.cause)
throw ServiceException(
errMssg ?: "ExportTaskAssistArchive failed",
operation = FeatureDevOperation.ExportTaskAssistArchiveResult.toString(),
desc = null,
e.cause
)
}

val parsedResult: ExportDocTaskAssistResultArchiveStreamResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ const val DEFAULT_RETRY_LIMIT = 0
const val MAX_PROJECT_SIZE_BYTES: Long = 200 * 1024 * 1024

val CLIENT_ERROR_MESSAGES = setOf(
"Improperly formed request",
"Resource not found",
"StartTaskAssistCodeGeneration reached for this month.",
"The folder you chose did not contain any source files in a supported language. Choose another folder and try again.",
"reached the quota for number of iterations on code generation."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,52 +24,80 @@ open class FeatureDevException(override val message: String?, val operation: Str
}
}

/**
* Exceptions extending this class are considered "errors" in service metrics.
*/
open class ClientException(message: String, operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message, operation, desc, cause)

/**
* Errors extending this class are considered "faults" in service metrics.
*/
open class ServiceException(message: String, operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message, operation, desc, cause)

/**
* Errors extending this class are considered "LLM failures" in service metrics.
*/
open class LlmException(message: String, operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message, operation, desc, cause)


object ApiException {
fun of(statusCode: Int, message: String, operation: String, desc: String?, cause: Throwable? = null): FeatureDevException =
when (statusCode in 400..499) {
true -> ClientException(message, operation, desc, cause)
false -> ServiceException(message, operation, desc, cause)
}
}


class NoChangeRequiredException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.exception.no_change_required_exception"), operation, desc, cause)
ClientException(message("amazonqFeatureDev.exception.no_change_required_exception"), operation, desc, cause)

class EmptyPatchException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.exception.guardrails"), operation, desc, cause)
LlmException(message("amazonqFeatureDev.exception.guardrails"), operation, desc, cause)

class ContentLengthException(
override val message: String = message("amazonqFeatureDev.content_length.error_text"),
operation: String,
desc: String?,
cause: Throwable? = null,
) :
RepoSizeError, FeatureDevException(message, operation, desc, cause)
RepoSizeError, ClientException(message, operation, desc, cause)

class ZipFileCorruptedException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException("The zip file is corrupted", operation, desc, cause)
ServiceException("The zip file is corrupted", operation, desc, cause)

class UploadURLExpired(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.exception.upload_url_expiry"), operation, desc, cause)
ClientException(message("amazonqFeatureDev.exception.upload_url_expiry"), operation, desc, cause)

class CodeIterationLimitException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.code_generation.iteration_limit.error_text"), operation, desc, cause)
ClientException(message("amazonqFeatureDev.code_generation.iteration_limit.error_text"), operation, desc, cause)

class MonthlyConversationLimitError(message: String, operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message, operation, desc, cause)
ClientException(message, operation, desc, cause)

class GuardrailsException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.exception.guardrails"), operation, desc, cause)
ClientException(message("amazonqFeatureDev.exception.guardrails"), operation, desc, cause)

class PromptRefusalException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.exception.prompt_refusal"), operation, desc, cause)
ClientException(message("amazonqFeatureDev.exception.prompt_refusal"), operation, desc, cause)

class ThrottlingException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.exception.throttling"), operation, desc, cause)
ClientException(message("amazonqFeatureDev.exception.throttling"), operation, desc, cause)

class ExportParseException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.exception.export_parsing_error"), operation, desc, cause)
ServiceException(message("amazonqFeatureDev.exception.export_parsing_error"), operation, desc, cause)

class CodeGenerationException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.code_generation.failed_generation"), operation, desc, cause)
ServiceException(message("amazonqFeatureDev.code_generation.failed_generation"), operation, desc, cause)

class UploadCodeException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.exception.upload_code"), operation, desc, cause)
ServiceException(message("amazonqFeatureDev.exception.upload_code"), operation, desc, cause)

class ConversationIdNotFoundException(operation: String, desc: String?, cause: Throwable? = null) :
FeatureDevException(message("amazonqFeatureDev.exception.conversation_not_found"), operation, desc, cause)
ServiceException(message("amazonqFeatureDev.exception.conversation_not_found"), operation, desc, cause)

val denyListedErrors = arrayOf("Deserialization error", "Inaccessible host", "UnknownHost")
fun createUserFacingErrorMessage(message: String?): String? =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,11 @@ import com.intellij.notification.NotificationAction
import software.aws.toolkits.jetbrains.services.amazonq.messages.MessagePublisher
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.CLIENT_ERROR_MESSAGES
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.CODE_GENERATION_RETRY_LIMIT
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.CodeIterationLimitException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ContentLengthException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.EmptyPatchException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.GuardrailsException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ClientException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.LlmException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.MetricDataOperationName
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.MetricDataResult
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.MonthlyConversationLimitError
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.NoChangeRequiredException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.PromptRefusalException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ThrottlingException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ZipFileCorruptedException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ServiceException
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.FeatureDevMessageType
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.FollowUp
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.FollowUpStatusType
Expand Down Expand Up @@ -158,43 +152,34 @@ suspend fun FeatureDevController.onCodeGeneration(
messenger.sendSystemPrompt(tabId = tabId, followUp = getFollowUpOptions(session.sessionState.phase, InsertAction.ALL))
messenger.sendUpdatePlaceholder(tabId = tabId, newPlaceholder = message("amazonqFeatureDev.placeholder.after_code_generation"))
} catch (err: Exception) {
val metricDataResult: MetricDataResult
when (err) {
is GuardrailsException,
is NoChangeRequiredException,
is PromptRefusalException,
is ThrottlingException,
is CodeIterationLimitException,
is MonthlyConversationLimitError,
is ContentLengthException,
is ZipFileCorruptedException,
is ClientException,
-> {
session.sendMetricDataTelemetry(
MetricDataOperationName.EndCodeGeneration,
MetricDataResult.Error
)
metricDataResult = MetricDataResult.Error
}

is LlmException -> {
metricDataResult = MetricDataResult.LlmFailure
}
is EmptyPatchException -> {
session.sendMetricDataTelemetry(
MetricDataOperationName.EndCodeGeneration,
MetricDataResult.LlmFailure
)

is ServiceException -> {
metricDataResult = MetricDataResult.Fault
}

else -> {
val errorMessage = err.message.orEmpty()

if (CLIENT_ERROR_MESSAGES.any { errorMessage.contains(it) }) {
session.sendMetricDataTelemetry(
MetricDataOperationName.EndCodeGeneration,
MetricDataResult.Error
)
metricDataResult = if (CLIENT_ERROR_MESSAGES.any { errorMessage.contains(it) }) {
MetricDataResult.Error
} else {
session.sendMetricDataTelemetry(
MetricDataOperationName.EndCodeGeneration,
MetricDataResult.Fault
)
MetricDataResult.Fault
}
}
}
session.sendMetricDataTelemetry(
MetricDataOperationName.EndCodeGeneration,
metricDataResult
)
throw err
} finally {
if (session.sessionState.token
Expand Down
Loading
Loading