IDEA-310984 Usage view statistics collector: added popup.closed event

Added getEventData() ShowUsagesActionHandler for statistcs reporting purposes

`popup.closed` logs:
* UsageView
* if item choseor not
* target element language
* selected element class
* duration of being shown
* added target element for the statistics

GitOrigin-RevId: c20865b9190c82809181bd0a4cb298c765b3acc3
This commit is contained in:
Andrey Sokolov
2023-01-20 13:28:38 +01:00
committed by intellij-monorepo-bot
parent 27fba5b6c8
commit b1a6bdab2f
4 changed files with 69 additions and 9 deletions

View File

@@ -7,6 +7,7 @@ import com.intellij.find.usages.api.UsageOptions.createOptions
import com.intellij.find.usages.impl.AllSearchOptions
import com.intellij.find.usages.impl.buildUsageViewQuery
import com.intellij.ide.nls.NlsMessages
import com.intellij.internal.statistic.eventLog.events.EventPair
import com.intellij.lang.LangBundle
import com.intellij.lang.Language
import com.intellij.openapi.project.Project
@@ -68,6 +69,9 @@ internal data class ShowTargetUsagesActionHandler(
override fun getTargetLanguage(): Language? = null
override fun getTargetClass(): Class<*> = target::class.java
override fun getEventData(): List<EventPair<*>> {
return emptyList();
}
companion object {

View File

@@ -16,6 +16,8 @@ import com.intellij.ide.DataManager;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.ide.util.gotoByName.ModelDiff;
import com.intellij.ide.util.scopeChooser.ScopeChooserGroup;
import com.intellij.internal.statistic.eventLog.events.EventFields;
import com.intellij.internal.statistic.eventLog.events.EventPair;
import com.intellij.internal.statistic.service.fus.collectors.UIEventLogger;
import com.intellij.lang.Language;
import com.intellij.lang.injection.InjectedLanguageManager;
@@ -44,9 +46,7 @@ import com.intellij.openapi.ui.DialogPanel;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.OnePixelDivider;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.ui.popup.util.PopupUtil;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
@@ -373,6 +373,12 @@ public class ShowUsagesAction extends AnAction implements PopupAction, HintManag
public @NotNull Class<?> getTargetClass() {
return handler.getPsiElement().getClass();
}
@Override
public @NotNull List<EventPair<?>> getEventData() {
return List.of(UsageViewStatisticsCollector.PRIMARY_TARGET.with(handler.getPsiElement().getClass()),
EventFields.Language.with(handler.getPsiElement().getLanguage()));
}
};
}
@@ -414,7 +420,17 @@ public class ShowUsagesAction extends AnAction implements PopupAction, HintManag
AbstractPopup popup = createUsagePopup(usageView, showUsagesPopupData, itemChosenCallback, tableResizer);
popup.addResizeListener(() -> manuallyResized.set(true), popup);
Ref<Long> popupShownTime = new Ref<>();
popup.addListener(new JBPopupListener() {
@Override
public void onClosed(@NotNull LightweightWindowEvent event) {
Object usageNode = table.getModel().getValueAt(table.getSelectedRow(), 0);
UsageInfo2UsageAdapter usageAdapter = getSelectedUsageAdapter(ObjectUtils.tryCast(usageNode, UsageNode.class));
UsageViewStatisticsCollector.logPopupClosed(project, usageView, event.isOk(),
usageAdapter,
popupShownTime.get(), actionHandler.getEventData());
}
});
ProgressIndicator indicator = new ProgressIndicatorBase();
if (!popup.isDisposed()) {
Disposer.register(popup, usageView);
@@ -423,7 +439,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction, HintManag
// show popup only if find usages takes more than 300ms, otherwise it would flicker needlessly
EdtScheduledExecutorService.getInstance().schedule(() -> {
if (!usageView.isDisposed()) {
showPopupIfNeedTo(popup, parameters.popupPosition);
showPopupIfNeedTo(popup, parameters.popupPosition, popupShownTime);
}
}, ourPopupDelayTimeout, TimeUnit.MILLISECONDS);
}
@@ -438,7 +454,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction, HintManag
List<Usage> copy;
synchronized (usages) {
// open up popup as soon as the first usage has been found
if (!popup.isVisible() && (usages.isEmpty() || !showPopupIfNeedTo(popup, parameters.popupPosition))) {
if (!popup.isVisible() && (usages.isEmpty() || !showPopupIfNeedTo(popup, parameters.popupPosition, popupShownTime))) {
return;
}
addUsageNodes(usageView.getRoot(), usageView, nodes);
@@ -618,9 +634,10 @@ public class ShowUsagesAction extends AnAction implements PopupAction, HintManag
return __ -> false;
}
private static boolean showPopupIfNeedTo(@NotNull JBPopup popup, @NotNull RelativePoint popupPosition) {
private static boolean showPopupIfNeedTo(@NotNull JBPopup popup, @NotNull RelativePoint popupPosition, Ref<Long> popupShownTime) {
if (!popup.isDisposed() && !popup.isVisible()) {
popup.show(popupPosition);
popupShownTime.set(System.currentTimeMillis());
return true;
}
return false;
@@ -1032,6 +1049,14 @@ public class ShowUsagesAction extends AnAction implements PopupAction, HintManag
return (int)usages.stream().filter(usage -> !usageView.isVisible(usage)).count();
}
private static @Nullable UsageInfo2UsageAdapter getSelectedUsageAdapter(@Nullable UsageNode usageNode) {
UsageInfo2UsageAdapter usageAdapter = null;
if (usageNode != null) {
usageAdapter = ObjectUtils.tryCast(usageNode.getUsage(), UsageInfo2UsageAdapter.class);
}
return usageAdapter;
}
private static int getUsageOffset(@NotNull Usage usage) {
if (!(usage instanceof UsageInfo2UsageAdapter)) return -1;
PsiElement element = ((UsageInfo2UsageAdapter)usage).getElement();

View File

@@ -2,6 +2,7 @@
package com.intellij.find.actions;
import com.intellij.find.FindBundle;
import com.intellij.internal.statistic.eventLog.events.EventPair;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.keymap.KeymapUtil;
@@ -13,6 +14,8 @@ import com.intellij.usages.UsageSearcher;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
interface ShowUsagesActionHandler {
boolean isValid();
@@ -35,6 +38,8 @@ interface ShowUsagesActionHandler {
@NotNull Class<?> getTargetClass();
@NotNull List<EventPair<?>> getEventData();
static @PopupAdvertisement @Nullable String getSecondInvocationHint(@NotNull ShowUsagesActionHandler actionHandler) {
KeyboardShortcut shortcut = ShowUsagesAction.getShowUsagesShortcut();
if (shortcut == null) {

View File

@@ -5,6 +5,7 @@ import com.intellij.ide.util.scopeChooser.ScopeIdMapper
import com.intellij.internal.statistic.eventLog.EventLogGroup
import com.intellij.internal.statistic.eventLog.FeatureUsageData
import com.intellij.internal.statistic.eventLog.events.EventFields
import com.intellij.internal.statistic.eventLog.events.EventPair
import com.intellij.internal.statistic.eventLog.events.PrimitiveEventField
import com.intellij.internal.statistic.eventLog.validator.ValidationResultType
import com.intellij.internal.statistic.eventLog.validator.rules.EventContext
@@ -16,8 +17,10 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.search.SearchScope
import com.intellij.usageView.UsageInfo
import com.intellij.usages.Usage
import com.intellij.usages.UsageInfo2UsageAdapter
import com.intellij.usages.UsageView
import com.intellij.usages.rules.PsiElementUsage
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.annotations.Nls
enum class CodeNavigateSource {
@@ -35,7 +38,7 @@ class UsageViewStatisticsCollector : CounterUsagesCollector() {
override fun getGroup() = GROUP
companion object {
val GROUP = EventLogGroup("usage.view", 16)
val GROUP = EventLogGroup("usage.view", 17)
val USAGE_VIEW = object : PrimitiveEventField<UsageView?>() {
override val name: String = "usage_view"
@@ -46,7 +49,9 @@ class UsageViewStatisticsCollector : CounterUsagesCollector() {
override val validationRule: List<String>
get() = listOf("{regexp#integer}")
}
private val PRIMARY_TARGET = EventFields.Class("primary_target")
@JvmField
val PRIMARY_TARGET = EventFields.Class("primary_target")
private val REFERENCE_CLASS = EventFields.Class("reference_class")
private val UI_LOCATION = EventFields.Enum("ui_location", CodeNavigateSource::class.java)
private val USAGE_SHOWN = GROUP.registerVarargEvent("usage.shown", USAGE_VIEW, REFERENCE_CLASS, EventFields.Language, UI_LOCATION)
@@ -102,6 +107,10 @@ class UsageViewStatisticsCollector : CounterUsagesCollector() {
private val scopeChanged = GROUP.registerVarargEvent("scope.changed", USAGE_VIEW, PREVIOUS_SCOPE, NEW_SCOPE, SYMBOL_CLASS)
private val OPEN_IN_FIND_TOOL_WINDOW = GROUP.registerEvent("open.in.tool.window", USAGE_VIEW)
private val USER_ACTION = EventFields.Enum("userAction", TooManyUsagesUserAction::class.java)
private val ITEM_CHOSEN = EventFields.Boolean("item_chosen")
private val popupClosed = GROUP.registerVarargEvent(
"popup.closed", USAGE_VIEW, ITEM_CHOSEN, PRIMARY_TARGET, EventFields.Language, REFERENCE_CLASS, EventFields.DurationMs
)
private val tooManyUsagesDialog = GROUP.registerVarargEvent("tooManyResultsDialog",
USAGE_VIEW,
USER_ACTION,
@@ -264,6 +273,23 @@ class UsageViewStatisticsCollector : CounterUsagesCollector() {
fun logOpenInFindToolWindow(project: Project?, usageView: UsageView) =
OPEN_IN_FIND_TOOL_WINDOW.log(project, usageView)
@JvmStatic
fun logPopupClosed(project: Project?,
usageView: UsageView,
itemChosen: Boolean,
usage: UsageInfo2UsageAdapter?,
startTime: Long?,
showUsagesHandlerEventData: List<EventPair<*>>) {
val data = mutableListOf(USAGE_VIEW.with(usageView), ITEM_CHOSEN.with(itemChosen),
REFERENCE_CLASS.with(
usage?.referenceClass
))
data.addAll(showUsagesHandlerEventData)
if (startTime != null) {
data.add(EventFields.DurationMs.with(System.currentTimeMillis() - startTime))
}
popupClosed.log(project, data)
}
}
}