Skip to content

Commit ba427a9

Browse files
authored
Q Code Transform refactor: Add CodeTransformTelemetryManager to centralize CodeTransform telemetry emission. (#4190)
* Add CodeTransformTelemetryManager. --------- Co-authored-by: Leonardo Araneda Freccero <[email protected]>
1 parent e66846c commit ba427a9

File tree

15 files changed

+331
-284
lines changed

15 files changed

+331
-284
lines changed

plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,18 @@ import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope
2121
import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
2222
import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact
2323
import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId
24-
import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModernizerSessionState
25-
import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeTransformTelemetryState
2624
import software.aws.toolkits.jetbrains.services.codemodernizer.summary.CodeModernizerSummaryEditorProvider
2725
import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
2826
import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
2927
import software.aws.toolkits.resources.message
30-
import software.aws.toolkits.telemetry.CodeTransformPatchViewerCancelSrcComponents
31-
import software.aws.toolkits.telemetry.CodeTransformVCSViewerSrcComponents
32-
import software.aws.toolkits.telemetry.CodetransformTelemetry
3328
import java.nio.file.Files
3429
import java.nio.file.Path
3530
import java.time.Instant
3631
import java.util.concurrent.atomic.AtomicBoolean
3732

3833
data class DownloadArtifactResult(val artifact: CodeModernizerArtifact?, val zipPath: String)
3934
class ArtifactHandler(private val project: Project, private val clientAdaptor: GumbyClient) {
35+
private val telemetry = CodeTransformTelemetryManager.getInstance(project)
4036
private val downloadedArtifacts = mutableMapOf<JobId, Path>()
4137
private val downloadedSummaries = mutableMapOf<JobId, TransformationSummary>()
4238

@@ -103,15 +99,14 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
10399
output
104100
} catch (e: RuntimeException) {
105101
LOG.error { e.message.toString() }
106-
telemetryErrorMessage = "Unexpected error when downloading result"
102+
telemetryErrorMessage = "Unexpected error when downloading result ${e.localizedMessage}"
107103
DownloadArtifactResult(null, zipPath)
108104
} finally {
109-
CodetransformTelemetry.jobArtifactDownloadAndDeserializeTime(
110-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
111-
codeTransformRunTimeLatency = calculateTotalLatency(downloadStartTime, Instant.now()),
112-
codeTransformJobId = job.id,
113-
codeTransformTotalByteSize = totalDownloadBytes,
114-
codeTransformRuntimeError = telemetryErrorMessage,
105+
telemetry.jobArtifactDownloadAndDeserializeTime(
106+
downloadStartTime,
107+
job,
108+
totalDownloadBytes,
109+
telemetryErrorMessage,
115110
)
116111
}
117112
} catch (e: Exception) {
@@ -142,24 +137,11 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
142137
)
143138
dialog.isModal = true
144139

145-
CodetransformTelemetry.vcsDiffViewerVisible(
146-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
147-
codeTransformJobId = jobId.id,
148-
)
149-
140+
telemetry.vcsDiffViewerVisible(jobId)
150141
if (dialog.showAndGet()) {
151-
CodetransformTelemetry.vcsViewerSubmitted(
152-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
153-
codeTransformJobId = jobId.id,
154-
codeTransformStatus = CodeModernizerSessionState.getInstance(project).currentJobStatus.toString(),
155-
)
142+
telemetry.vcsViewerSubmitted(jobId)
156143
} else {
157-
CodetransformTelemetry.vcsViewerCanceled(
158-
codeTransformPatchViewerCancelSrcComponents = CodeTransformPatchViewerCancelSrcComponents.CancelButton,
159-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
160-
codeTransformJobId = jobId.id,
161-
codeTransformStatus = CodeModernizerSessionState.getInstance(project).currentJobStatus.toString(),
162-
)
144+
telemetry.vscViewerCancelled(jobId)
163145
}
164146
}
165147
}
@@ -185,11 +167,7 @@ class ArtifactHandler(private val project: Project, private val clientAdaptor: G
185167
}
186168

187169
fun displayDiffAction(jobId: JobId) = runReadAction {
188-
CodetransformTelemetry.vcsViewerClicked(
189-
codeTransformVCSViewerSrcComponents = CodeTransformVCSViewerSrcComponents.ToastNotification,
190-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
191-
codeTransformJobId = jobId.id,
192-
)
170+
telemetry.vcsViewerClicked(jobId)
193171
projectCoroutineScope(project).launch {
194172
displayDiff(jobId)
195173
}

plugins/toolkit/jetbrains-core/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt

Lines changed: 12 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import com.intellij.openapi.wm.ToolWindowManager
2121
import kotlinx.coroutines.Job
2222
import kotlinx.coroutines.delay
2323
import kotlinx.coroutines.launch
24-
import org.apache.commons.codec.digest.DigestUtils
2524
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationJob
2625
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationPlan
2726
import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus
@@ -48,7 +47,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.model.ValidationR
4847
import software.aws.toolkits.jetbrains.services.codemodernizer.panels.managers.CodeModernizerBottomWindowPanelManager
4948
import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModernizerSessionState
5049
import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModernizerState
51-
import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeTransformTelemetryState
5250
import software.aws.toolkits.jetbrains.services.codemodernizer.state.StateFlags
5351
import software.aws.toolkits.jetbrains.services.codemodernizer.state.buildState
5452
import software.aws.toolkits.jetbrains.services.codemodernizer.state.getLatestJobId
@@ -61,21 +59,17 @@ import software.aws.toolkits.jetbrains.utils.notifyStickyError
6159
import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
6260
import software.aws.toolkits.resources.message
6361
import software.aws.toolkits.telemetry.CodeTransformCancelSrcComponents
64-
import software.aws.toolkits.telemetry.CodeTransformJavaSourceVersionsAllowed
65-
import software.aws.toolkits.telemetry.CodeTransformJavaTargetVersionsAllowed
6662
import software.aws.toolkits.telemetry.CodeTransformPreValidationError
6763
import software.aws.toolkits.telemetry.CodeTransformStartSrcComponents
68-
import software.aws.toolkits.telemetry.CodetransformTelemetry
69-
import software.aws.toolkits.telemetry.Result
7064
import java.time.Instant
71-
import java.util.Base64
7265
import java.util.concurrent.atomic.AtomicBoolean
7366
import javax.swing.Icon
7467

7568
const val AMAZON_Q_FEEDBACK_DIALOG_KEY = "Amazon Q"
7669

7770
@State(name = "codemodernizerStates", storages = [Storage("aws.xml", roamingType = RoamingType.PER_OS)])
7871
class CodeModernizerManager(private val project: Project) : PersistentStateComponent<CodeModernizerState>, Disposable {
72+
private val telemetry = CodeTransformTelemetryManager.getInstance(project)
7973
private var managerState = CodeModernizerState()
8074
val codeModernizerBottomWindowPanelManager by lazy { CodeModernizerBottomWindowPanelManager(project) }
8175
private val codeModernizerBottomWindowPanelContent by lazy {
@@ -204,11 +198,11 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
204198

205199
fun validateAndStart(srcStartComponent: CodeTransformStartSrcComponents = CodeTransformStartSrcComponents.DevToolsStartButton) =
206200
projectCoroutineScope(project).launch {
207-
sendUserClickedTelemetry(srcStartComponent)
201+
telemetry.sendUserClickedTelemetry(srcStartComponent)
208202
if (isModernizationInProgress.getAndSet(true)) return@launch
209203
val validationResult = validate(project)
210204
runInEdt {
211-
sendValidationResultTelemetry(validationResult)
205+
telemetry.sendValidationResult(validationResult)
212206
if (validationResult.valid) {
213207
runModernize(validationResult.validatedBuildFiles) ?: isModernizationInProgress.set(false)
214208
} else {
@@ -218,58 +212,17 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
218212
}
219213
}
220214

221-
private fun sendUserClickedTelemetry(srcStartComponent: CodeTransformStartSrcComponents) {
222-
CodeTransformTelemetryState.instance.setSessionId()
223-
CodeTransformTelemetryState.instance.setStartTime()
224-
CodetransformTelemetry.isDoubleClickedToTriggerUserModal(
225-
codeTransformStartSrcComponents = srcStartComponent,
226-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
227-
)
228-
}
229-
230-
private fun sendValidationResultTelemetry(validationResult: ValidationResult, onProjectFirstOpen: Boolean = false) {
231-
// Old telemetry event to be fired only when users click on transform
232-
if (!validationResult.valid && !onProjectFirstOpen) {
233-
CodetransformTelemetry.isDoubleClickedToTriggerInvalidProject(
234-
codeTransformPreValidationError = validationResult.invalidTelemetryReason.category ?: CodeTransformPreValidationError.Unknown,
235-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
236-
result = Result.Failed,
237-
reason = validationResult.invalidTelemetryReason.additonalInfo
238-
)
239-
}
240-
// New projectDetails metric should always be fired whether the project was valid or invalid
241-
CodetransformTelemetry.projectDetails(
242-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
243-
result = if (!validationResult.valid) Result.Failed else Result.Succeeded,
244-
reason = if (!validationResult.valid) validationResult.invalidTelemetryReason.additonalInfo else null,
245-
codeTransformPreValidationError = validationResult.invalidTelemetryReason.category ?: CodeTransformPreValidationError.Unknown,
246-
codeTransformLocalJavaVersion = project.tryGetJdk().toString()
247-
)
248-
}
249-
250215
fun stopModernize() {
251216
if (isModernizationJobActive()) {
252217
userInitiatedStopCodeModernization()
253-
CodetransformTelemetry.jobIsCancelledByUser(
254-
codeTransformCancelSrcComponents = CodeTransformCancelSrcComponents.DevToolsStopButton,
255-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId()
256-
)
218+
telemetry.jobIsCancelledByUser(CodeTransformCancelSrcComponents.DevToolsStopButton)
257219
}
258220
}
259221

260-
private fun calculateProjectHash(customerSelection: CustomerSelection) = Base64
261-
.getEncoder()
262-
.encodeToString(DigestUtils.sha256(customerSelection.configurationFile.path))
263-
264222
fun runModernize(validatedBuildFiles: List<VirtualFile>): Job? {
265223
initStopParameters()
266224
val customerSelection = getCustomerSelection(validatedBuildFiles) ?: return null
267-
CodetransformTelemetry.jobStartedCompleteFromPopupDialog(
268-
codeTransformJavaSourceVersionsAllowed = CodeTransformJavaSourceVersionsAllowed.from(customerSelection.sourceJavaVersion.name),
269-
codeTransformJavaTargetVersionsAllowed = CodeTransformJavaTargetVersionsAllowed.from(customerSelection.targetJavaVersion.name),
270-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
271-
codeTransformProjectId = calculateProjectHash(customerSelection),
272-
)
225+
telemetry.jobStartedCompleteFromPopupDialog(customerSelection)
273226
initModernizationJobUI(true, project.getModuleOrProjectNameForFile(customerSelection.configurationFile))
274227
val session = createCodeModernizerSession(customerSelection, project)
275228
codeTransformationSession = session
@@ -479,7 +432,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
479432
// Gather project details
480433
if (onProjectFirstOpen) {
481434
val validationResult = validate(project)
482-
sendValidationResultTelemetry(validationResult, onProjectFirstOpen)
435+
telemetry.sendValidationResult(validationResult, onProjectFirstOpen)
483436
}
484437

485438
val context = managerState.toSessionContext(project)
@@ -541,11 +494,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
541494
)
542495
}
543496
}
544-
CodetransformTelemetry.jobIsResumedAfterIdeClose(
545-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
546-
codeTransformJobId = lastJobId.id,
547-
codeTransformStatus = result.status().toString()
548-
)
497+
telemetry.jobIsResumedAfterIdeClose(lastJobId, result.status())
549498
} catch (e: AccessDeniedException) {
550499
LOG.error { "Unable to resume job as credentials are invalid" }
551500
// User is logged in with old or invalid credentials, nothing to do until they log in with valid credentials
@@ -641,14 +590,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
641590
listOf(openTroubleshootingGuideNotificationAction(TROUBLESHOOTING_URL_PREREQUISITES), displayFeedbackNotificationAction()),
642591
)
643592
}
644-
CodetransformTelemetry.totalRunTime(
645-
codeTransformJobId = jobId?.toString(),
646-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
647-
codeTransformResultStatusMessage = result.toString(),
648-
codeTransformRunTimeLatency = calculateTotalLatency(CodeTransformTelemetryState.instance.getStartTime(), Instant.now()),
649-
codeTransformLocalJavaVersion = getJavaVersionFromProjectSetting(project),
650-
codeTransformLocalMavenVersion = getMavenVersion(project),
651-
)
593+
telemetry.totalRunTime(result.toString(), jobId)
652594
}
653595

654596
fun createCodeModernizerSession(customerSelection: CustomerSelection, project: Project) = CodeModernizerSession(
@@ -669,33 +611,19 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
669611
fun userInitiatedStopCodeModernization() {
670612
notifyTransformationStartStopping()
671613
if (transformationStoppedByUsr.getAndSet(true)) return
672-
val currentId = codeTransformationSession?.getActiveJobId()?.id
614+
val currentId = codeTransformationSession?.getActiveJobId()
673615
projectCoroutineScope(project).launch {
674616
try {
675-
val success = codeTransformationSession?.stopTransformation(currentId) ?: true // no session -> no job to stop
617+
val success = codeTransformationSession?.stopTransformation(currentId?.id) ?: true // no session -> no job to stop
676618
if (!success) {
677619
// This should not happen
678620
throw CodeModernizerException(message("codemodernizer.notification.info.transformation_start_stopping.as_no_response"))
679-
} else {
680-
// Code successfully stopped toast will display when post job is run after this
681-
CodetransformTelemetry.totalRunTime(
682-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
683-
codeTransformResultStatusMessage = "JobCancelled",
684-
codeTransformRunTimeLatency = calculateTotalLatency(CodeTransformTelemetryState.instance.getStartTime(), Instant.now()),
685-
codeTransformLocalJavaVersion = getJavaVersionFromProjectSetting(project),
686-
codeTransformLocalMavenVersion = getMavenVersion(project),
687-
)
688621
}
689622
} catch (e: Exception) {
690623
LOG.error(e) { e.message.toString() }
691624
notifyTransformationFailedToStop(e.localizedMessage)
692-
CodetransformTelemetry.totalRunTime(
693-
codeTransformSessionId = CodeTransformTelemetryState.instance.getSessionId(),
694-
codeTransformResultStatusMessage = "JobCancelled",
695-
codeTransformRunTimeLatency = calculateTotalLatency(CodeTransformTelemetryState.instance.getStartTime(), Instant.now()),
696-
codeTransformLocalJavaVersion = getJavaVersionFromProjectSetting(project),
697-
codeTransformLocalMavenVersion = getMavenVersion(project),
698-
)
625+
} finally {
626+
telemetry.totalRunTime("JobCancelled", currentId)
699627
}
700628
}
701629
}

0 commit comments

Comments
 (0)