Skip to content

Commit 246b317

Browse files
authored
telemetry(amazonq): createUpload metric for scans (#5444)
* telemetry(amazonq): createUpload metric for scans * remove telemetry override
1 parent 3c7a01d commit 246b317

File tree

3 files changed

+95
-32
lines changed

3 files changed

+95
-32
lines changed

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanException.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ open class CodeWhispererCodeScanException(override val message: String?) : Runti
99

1010
open class CodeWhispererCodeFixException(override val message: String?) : RuntimeException()
1111

12-
open class CodeWhispererCodeScanServerException(override val message: String?) : RuntimeException()
12+
open class CodeWhispererCodeScanServerException(
13+
override val message: String?,
14+
val requestId: String?,
15+
val requestServiceType: String?,
16+
val httpStatusCode: String?,
17+
) : RuntimeException()
1318

1419
internal fun noFileOpenError(): Nothing =
1520
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.no_file_open"))
@@ -29,8 +34,12 @@ internal fun fileFormatNotSupported(format: String): Nothing =
2934
internal fun fileTooLarge(): Nothing =
3035
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.file_too_large"))
3136

32-
internal fun codeScanServerException(errorMessage: String): Nothing =
33-
throw CodeWhispererCodeScanServerException(errorMessage)
37+
internal fun codeScanServerException(
38+
errorMessage: String,
39+
requestId: String? = null,
40+
requestServiceType: String? = null,
41+
httpStatusCode: String? = null,
42+
): Nothing = throw CodeWhispererCodeScanServerException(errorMessage, requestId, requestServiceType, httpStatusCode)
3443

3544
internal fun invalidSourceZipError(): Nothing =
3645
throw CodeWhispererCodeScanException(message("codewhisperer.codescan.invalid_source_zip_telemetry"))

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanSession.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
105105
val artifactsUploadStartTime = now()
106106
val codeScanName = UUID.randomUUID().toString()
107107

108-
val taskType = if (sessionContext.codeAnalysisScope == CodeWhispererConstants.CodeAnalysisScope.PROJECT) {
109-
CodeWhispererConstants.UploadTaskType.SCAN_PROJECT
110-
} else {
108+
val taskType = if (isAutoScan()) {
111109
CodeWhispererConstants.UploadTaskType.SCAN_FILE
110+
} else {
111+
CodeWhispererConstants.UploadTaskType.SCAN_PROJECT
112112
}
113113

114114
val sourceZipUploadResponse =

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererZipUploadManager.kt

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.intellij.openapi.components.service
88
import com.intellij.openapi.project.Project
99
import com.intellij.util.io.HttpRequests
1010
import org.apache.commons.codec.digest.DigestUtils
11+
import software.amazon.awssdk.awscore.exception.AwsServiceException
1112
import software.amazon.awssdk.services.codewhispererruntime.model.CodeAnalysisUploadContext
1213
import software.amazon.awssdk.services.codewhispererruntime.model.CodeFixUploadContext
1314
import software.amazon.awssdk.services.codewhispererruntime.model.CreateUploadUrlRequest
@@ -21,6 +22,7 @@ import software.aws.toolkits.core.utils.debug
2122
import software.aws.toolkits.core.utils.getLogger
2223
import software.aws.toolkits.jetbrains.core.AwsClientManager
2324
import software.aws.toolkits.jetbrains.services.amazonq.RetryableOperation
25+
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanServerException
2426
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanSession.Companion.APPLICATION_ZIP
2527
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanSession.Companion.AWS_KMS
2628
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanSession.Companion.CONTENT_MD5
@@ -32,7 +34,11 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.codeScanS
3234
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.invalidSourceZipError
3335
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.CodeTestException
3436
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor
37+
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
3538
import software.aws.toolkits.resources.message
39+
import software.aws.toolkits.telemetry.AmazonqTelemetry
40+
import software.aws.toolkits.telemetry.AmazonqUploadIntent
41+
import software.aws.toolkits.telemetry.MetricResult
3642
import java.io.File
3743
import java.io.FileInputStream
3844
import java.io.IOException
@@ -50,29 +56,67 @@ class CodeWhispererZipUploadManager(private val project: Project) {
5056
taskName: String,
5157
featureUseCase: CodeWhispererConstants.FeatureName,
5258
): CreateUploadUrlResponse {
53-
// Throw error if zipFile is invalid.
54-
if (!zipFile.exists()) {
55-
when (featureUseCase) {
56-
CodeWhispererConstants.FeatureName.CODE_REVIEW -> invalidSourceZipError()
57-
CodeWhispererConstants.FeatureName.TEST_GENERATION -> testGenerationInvalidSourceZipError()
58-
else -> throw IllegalArgumentException("Unsupported feature case: $featureUseCase") // Adding else for safety check
59+
val startTime = System.currentTimeMillis()
60+
var result: MetricResult = MetricResult.Succeeded
61+
var failureReason: String? = null
62+
var failureReasonDesc: String? = null
63+
var requestId: String? = null
64+
var requestServiceType: String? = null
65+
var httpStatusCode: String? = null
66+
try {
67+
// Throw error if zipFile is invalid.
68+
if (!zipFile.exists()) {
69+
when (featureUseCase) {
70+
CodeWhispererConstants.FeatureName.CODE_REVIEW -> invalidSourceZipError()
71+
CodeWhispererConstants.FeatureName.TEST_GENERATION -> testGenerationInvalidSourceZipError()
72+
else -> throw IllegalArgumentException("Unsupported feature case: $featureUseCase") // Adding else for safety check
73+
}
5974
}
60-
}
61-
val fileMd5: String = Base64.getEncoder().encodeToString(DigestUtils.md5(FileInputStream(zipFile)))
62-
val createUploadUrlResponse = createUploadUrl(fileMd5, artifactType, taskType, taskName, featureUseCase)
63-
val url = createUploadUrlResponse.uploadUrl()
64-
LOG.debug { "$featureUseCase: Uploading $artifactType using the presigned URL." }
75+
val fileMd5: String = Base64.getEncoder().encodeToString(DigestUtils.md5(FileInputStream(zipFile)))
76+
val createUploadUrlResponse = createUploadUrl(fileMd5, artifactType, taskType, taskName, featureUseCase)
77+
val url = createUploadUrlResponse.uploadUrl()
78+
LOG.debug { "$featureUseCase: Uploading $artifactType using the presigned URL." }
6579

66-
uploadArtifactToS3(
67-
url,
68-
createUploadUrlResponse.uploadId(),
69-
zipFile,
70-
fileMd5,
71-
createUploadUrlResponse.kmsKeyArn(),
72-
createUploadUrlResponse.requestHeaders(),
73-
featureUseCase
74-
)
75-
return createUploadUrlResponse
80+
uploadArtifactToS3(
81+
url,
82+
createUploadUrlResponse.uploadId(),
83+
zipFile,
84+
fileMd5,
85+
createUploadUrlResponse.kmsKeyArn(),
86+
createUploadUrlResponse.requestHeaders(),
87+
featureUseCase
88+
)
89+
return createUploadUrlResponse
90+
} catch (e: Exception) {
91+
result = MetricResult.Failed
92+
failureReason = e.javaClass.simpleName
93+
failureReasonDesc = e.message
94+
if (e is CodeWhispererCodeScanServerException) {
95+
requestId = e.requestId
96+
requestServiceType = e.requestServiceType
97+
httpStatusCode = e.httpStatusCode
98+
}
99+
throw e
100+
} finally {
101+
if (featureUseCase == CodeWhispererConstants.FeatureName.CODE_REVIEW) {
102+
AmazonqTelemetry.createUpload(
103+
amazonqConversationId = "",
104+
amazonqUploadIntent = if (taskType == CodeWhispererConstants.UploadTaskType.SCAN_PROJECT) {
105+
AmazonqUploadIntent.FULLPROJECTSECURITYSCAN
106+
} else {
107+
AmazonqUploadIntent.AUTOMATICFILESECURITYSCAN
108+
},
109+
result = result,
110+
reason = failureReason,
111+
reasonDesc = failureReasonDesc,
112+
duration = (System.currentTimeMillis() - startTime).toDouble(),
113+
credentialStartUrl = getStartUrl(project),
114+
requestId = requestId,
115+
requestServiceType = requestServiceType,
116+
httpStatusCode = httpStatusCode
117+
)
118+
}
119+
}
76120
}
77121

78122
@Throws(IOException::class)
@@ -85,6 +129,7 @@ class CodeWhispererZipUploadManager(private val project: Project) {
85129
requestHeaders: Map<String, String>?,
86130
featureUseCase: CodeWhispererConstants.FeatureName,
87131
) {
132+
var connection: HttpURLConnection? = null
88133
RetryableOperation<Unit>().execute(
89134
operation = {
90135
val uploadIdJson = """{"uploadId":"$uploadId"}"""
@@ -103,9 +148,9 @@ class CodeWhispererZipUploadManager(private val project: Project) {
103148
}
104149
}
105150
}.connect {
106-
val connection = it.connection as HttpURLConnection
107-
connection.setFixedLengthStreamingMode(fileToUpload.length())
108-
IoUtils.copy(fileToUpload.inputStream(), connection.outputStream)
151+
connection = it.connection as HttpURLConnection
152+
connection?.setFixedLengthStreamingMode(fileToUpload.length())
153+
IoUtils.copy(fileToUpload.inputStream(), connection?.outputStream)
109154
}
110155
},
111156
isRetryable = { e ->
@@ -118,7 +163,12 @@ class CodeWhispererZipUploadManager(private val project: Project) {
118163
val errorMessage = getTelemetryErrorMessage(e, featureUseCase)
119164
when (featureUseCase) {
120165
CodeWhispererConstants.FeatureName.CODE_REVIEW ->
121-
codeScanServerException("CreateUploadUrlException: $errorMessage")
166+
codeScanServerException(
167+
"CreateUploadUrlException: $errorMessage",
168+
connection?.getHeaderField("x-amz-request-id"),
169+
"s3",
170+
(e as? HttpRequests.HttpStatusException)?.statusCode.toString()
171+
)
122172
CodeWhispererConstants.FeatureName.TEST_GENERATION ->
123173
throw CodeTestException(
124174
"UploadTestArtifactToS3Error: $errorMessage",
@@ -162,7 +212,11 @@ class CodeWhispererZipUploadManager(private val project: Project) {
162212
val errorMessage = getTelemetryErrorMessage(e, featureUseCase)
163213
when (featureUseCase) {
164214
CodeWhispererConstants.FeatureName.CODE_REVIEW ->
165-
codeScanServerException("CreateUploadUrlException after $attempts attempts: $errorMessage")
215+
codeScanServerException(
216+
"CreateUploadUrlException after $attempts attempts: $errorMessage",
217+
requestId = (e as? AwsServiceException)?.requestId(),
218+
httpStatusCode = (e as? AwsServiceException)?.statusCode().toString()
219+
)
166220

167221
CodeWhispererConstants.FeatureName.TEST_GENERATION ->
168222
throw CodeTestException(

0 commit comments

Comments
 (0)