mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-CR-48136: FUS: record numerical fields if settings reporting is enabled (FUS-444)
(cherry picked from commit bdf5420031054affd584a7b9099e4a2fc496623f) GitOrigin-RevId: e5c4a5b6fc50bf3bf39f7f4cfc7687888af99cb4
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a37e5e0577
commit
29bdecfcdd
+39
-15
@@ -6,17 +6,19 @@ import com.intellij.internal.statistic.eventLog.EventLogGroup
|
||||
import com.intellij.internal.statistic.eventLog.fus.FeatureUsageLogger
|
||||
import com.intellij.internal.statistic.utils.getPluginInfo
|
||||
import com.intellij.internal.statistic.utils.getProjectId
|
||||
import com.intellij.openapi.components.ReportValue
|
||||
import com.intellij.openapi.components.State
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.concurrency.NonUrgentExecutor
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.serialization.MutableAccessor
|
||||
import com.intellij.util.xmlb.BeanBinding
|
||||
import org.jdom.Element
|
||||
import java.util.*
|
||||
|
||||
private val LOG = Logger.getInstance("com.intellij.configurationStore.statistic.eventLog.FeatureUsageSettingsEventPrinter")
|
||||
private val GROUP = EventLogGroup("settings", 3)
|
||||
private val GROUP = EventLogGroup("settings", 4)
|
||||
|
||||
private val recordedComponents: MutableSet<String> = ContainerUtil.newConcurrentSet()
|
||||
private val recordedOptionNames: MutableSet<String> = ContainerUtil.newConcurrentSet()
|
||||
@@ -91,20 +93,15 @@ open class FeatureUsageSettingsEventPrinter(private val recordDefault: Boolean)
|
||||
for (accessor in accessors) {
|
||||
val type = accessor.genericType
|
||||
if (type === Boolean::class.javaPrimitiveType) {
|
||||
val value = accessor.readUnsafe(state)
|
||||
val isDefault = !jdomSerializer.getDefaultSerializationFilter().accepts(accessor, state)
|
||||
if (!isDefault || recordDefault) {
|
||||
recordedOptionNames.add(accessor.name)
|
||||
val content = HashMap<String, Any>()
|
||||
content["component"] = componentName
|
||||
content["name"] = accessor.name
|
||||
content["value"] = value
|
||||
if (recordDefault) {
|
||||
content["default"] = isDefault
|
||||
}
|
||||
addProjectOptions(content, isDefaultProject, hash)
|
||||
logConfig(GROUP, eventId, content)
|
||||
}
|
||||
logConfigValue(accessor, state, "bool", eventId, isDefaultProject, true, hash, componentName)
|
||||
}
|
||||
else if (type === Int::class.javaPrimitiveType || type === Long::class.javaPrimitiveType) {
|
||||
val reportValue = accessor.getAnnotation(ReportValue::class.java) != null
|
||||
logConfigValue(accessor, state, "int", eventId, isDefaultProject, reportValue, hash, componentName)
|
||||
}
|
||||
else if (type === Float::class.javaPrimitiveType || type === Double::class.javaPrimitiveType) {
|
||||
val reportValue = accessor.getAnnotation(ReportValue::class.java) != null
|
||||
logConfigValue(accessor, state, "float", eventId, isDefaultProject, reportValue, hash, componentName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +110,33 @@ open class FeatureUsageSettingsEventPrinter(private val recordDefault: Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
private fun logConfigValue(accessor: MutableAccessor,
|
||||
state: Any,
|
||||
type: String,
|
||||
eventId: String,
|
||||
isDefaultProject: Boolean,
|
||||
reportValue: Boolean,
|
||||
hash: String?,
|
||||
componentName: String) {
|
||||
val value = accessor.readUnsafe(state)
|
||||
val isDefault = !jdomSerializer.getDefaultSerializationFilter().accepts(accessor, state)
|
||||
if (!isDefault || recordDefault) {
|
||||
recordedOptionNames.add(accessor.name)
|
||||
val content = HashMap<String, Any>()
|
||||
content["type"] = type
|
||||
content["component"] = componentName
|
||||
content["name"] = accessor.name
|
||||
if (reportValue) {
|
||||
content["value"] = value
|
||||
}
|
||||
if (recordDefault) {
|
||||
content["default"] = isDefault
|
||||
}
|
||||
addProjectOptions(content, isDefaultProject, hash)
|
||||
logConfig(GROUP, eventId, content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addProjectOptions(content: HashMap<String, Any>,
|
||||
isDefaultProject: Boolean,
|
||||
projectHash: String?) {
|
||||
|
||||
+136
-17
@@ -5,11 +5,13 @@ import com.intellij.configurationStore.getStateSpec
|
||||
import com.intellij.configurationStore.statistic.eventLog.FeatureUsageSettingsEventPrinter
|
||||
import com.intellij.internal.statistic.eventLog.EventLogGroup
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
import com.intellij.openapi.components.ReportValue
|
||||
import com.intellij.openapi.components.State
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import com.intellij.testFramework.ProjectRule
|
||||
import com.intellij.testFramework.assertions.Assertions.assertThat
|
||||
import com.intellij.util.xmlb.annotations.Attribute
|
||||
import org.junit.Assert
|
||||
import org.junit.ClassRule
|
||||
import org.junit.Test
|
||||
|
||||
@@ -116,8 +118,8 @@ class FeatureUsageSettingsEventsTest {
|
||||
val withProject = true
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertDefaultState(printer.getOptionByName("boolOption"), "boolOption", false, withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", true, withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("boolOption"), "boolOption", false, "bool", withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", true, "bool", withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -174,7 +176,7 @@ class FeatureUsageSettingsEventsTest {
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -200,7 +202,7 @@ class FeatureUsageSettingsEventsTest {
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -215,8 +217,8 @@ class FeatureUsageSettingsEventsTest {
|
||||
val withProject = true
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", true, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
assertDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", true, "bool", withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -232,7 +234,7 @@ class FeatureUsageSettingsEventsTest {
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
@@ -248,8 +250,8 @@ class FeatureUsageSettingsEventsTest {
|
||||
val withProject = true
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(2)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", false, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", false, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -265,8 +267,76 @@ class FeatureUsageSettingsEventsTest {
|
||||
val defaultProject = false
|
||||
assertThat(printer.result).hasSize(3)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", false, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("boolOption"), "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("secondBoolOption"), "secondBoolOption", false, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `record default numerical fields in application component`() {
|
||||
val component = TestComponent()
|
||||
component.loadState(ComponentStateWithNumerical())
|
||||
val spec = getStateSpec(component)
|
||||
val printer = TestFeatureUsageSettingsEventsPrinter(false)
|
||||
printer.logConfigurationState(spec.name, component.state, null)
|
||||
|
||||
val withProject = false
|
||||
val defaultProject = false
|
||||
Assert.assertEquals(1, printer.result.size)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `record not default numerical fields in application component`() {
|
||||
val component = TestComponent()
|
||||
component.loadState(ComponentStateWithNumerical(intOpt = 10, longOpt = 15, floatOpt = 5.5F, doubleOpt = 3.4))
|
||||
val spec = getStateSpec(component)
|
||||
val printer = TestFeatureUsageSettingsEventsPrinter(false)
|
||||
printer.logConfigurationState(spec.name, component.state, null)
|
||||
|
||||
val withProject = false
|
||||
val defaultProject = false
|
||||
Assert.assertEquals(5, printer.result.size)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("integerOption"), "integerOption", null, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("longOption"), "longOption", null, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("floatOption"), "floatOption", null, "float", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("doubleOption"), "doubleOption", null, "float", false, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `record not default numerical fields with absolute value in application component`() {
|
||||
val component = TestComponent()
|
||||
component.loadState(ComponentStateWithNumerical(absIntOpt = 10, absLongOpt = 15, absFloatOpt = 5.5F, absDoubleOpt = 3.4))
|
||||
val spec = getStateSpec(component)
|
||||
val printer = TestFeatureUsageSettingsEventsPrinter(false)
|
||||
printer.logConfigurationState(spec.name, component.state, null)
|
||||
|
||||
val withProject = false
|
||||
val defaultProject = false
|
||||
Assert.assertEquals(5, printer.result.size)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absIntegerOption"), "absIntegerOption", 10, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absLongOption"), "absLongOption", 15L, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absFloatOption"), "absFloatOption", 5.5f, "float", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absDoubleOption"), "absDoubleOption", 3.4, "float", false, withProject, defaultProject)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `record all not default numerical fields with absolute value in application component`() {
|
||||
val component = TestComponent()
|
||||
component.loadState(ComponentStateWithNumerical(absIntOpt = 10, absLongOpt = 15, absFloatOpt = 5.5F, absDoubleOpt = 3.4))
|
||||
val spec = getStateSpec(component)
|
||||
val printer = TestFeatureUsageSettingsEventsPrinter(false)
|
||||
printer.logConfigurationState(spec.name, component.state, null)
|
||||
|
||||
val withProject = false
|
||||
val defaultProject = false
|
||||
Assert.assertEquals(5, printer.result.size)
|
||||
assertInvokedRecorded(printer.getInvokedEvent(), withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absIntegerOption"), "absIntegerOption", 10, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absLongOption"), "absLongOption", 15L, "int", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absFloatOption"), "absFloatOption", 5.5f, "float", false, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.getOptionByName("absDoubleOption"), "absDoubleOption", 3.4, "float", false, withProject, defaultProject)
|
||||
}
|
||||
|
||||
private fun assertDefaultWithoutDefaultRecording(printer: TestFeatureUsageSettingsEventsPrinter,
|
||||
@@ -276,14 +346,16 @@ class FeatureUsageSettingsEventsTest {
|
||||
assertInvokedRecorded(printer.result[0], withProject, defaultProject)
|
||||
}
|
||||
|
||||
private fun assertNotDefaultState(printer: TestFeatureUsageSettingsEventsPrinter, withRecordDefault: Boolean, withProject: Boolean, defaultProject: Boolean) {
|
||||
@Suppress("SameParameterValue")
|
||||
private fun assertNotDefaultState(printer: TestFeatureUsageSettingsEventsPrinter,withRecordDefault: Boolean, withProject: Boolean, defaultProject: Boolean) {
|
||||
assertThat(printer.result).hasSize(1)
|
||||
assertNotDefaultState(printer.result[0], "boolOption", true, withRecordDefault, withProject, defaultProject)
|
||||
assertNotDefaultState(printer.result[0], "boolOption", true, "bool", withRecordDefault, withProject, defaultProject)
|
||||
}
|
||||
|
||||
private fun assertNotDefaultState(event: LoggedComponentStateEvents,
|
||||
name: String,
|
||||
value: Any,
|
||||
value: Any?,
|
||||
type: String,
|
||||
withDefaultRecorded: Boolean,
|
||||
withProject: Boolean,
|
||||
defaultProject: Boolean) {
|
||||
@@ -292,14 +364,18 @@ class FeatureUsageSettingsEventsTest {
|
||||
assertThat(event.id).isEqualTo(if (withDefaultRecorded) "option" else "not.default")
|
||||
|
||||
var size = 3
|
||||
if (value != null) size++
|
||||
if (withDefaultRecorded) size++
|
||||
if (withProject) size++
|
||||
if (defaultProject) size++
|
||||
|
||||
assertThat(event.data).hasSize(size)
|
||||
assertThat(event.data["component"]).isEqualTo("MyTestComponent")
|
||||
assertThat(event.data["type"]).isEqualTo(type)
|
||||
assertThat(event.data["name"]).isEqualTo(name)
|
||||
assertThat(event.data["value"]).isEqualTo(value)
|
||||
if (value != null) {
|
||||
assertThat(event.data["value"]).isEqualTo(value)
|
||||
}
|
||||
if (withDefaultRecorded) {
|
||||
assertThat(event.data["default"]).isEqualTo(false)
|
||||
}
|
||||
@@ -313,24 +389,26 @@ class FeatureUsageSettingsEventsTest {
|
||||
|
||||
private fun assertDefaultState(printer: TestFeatureUsageSettingsEventsPrinter, withProject: Boolean, defaultProject: Boolean) {
|
||||
assertThat(printer.result).hasSize(1)
|
||||
assertDefaultState(printer.result[0], "boolOption", false, withProject, defaultProject)
|
||||
assertDefaultState(printer.result[0], "boolOption", false, "bool", withProject, defaultProject)
|
||||
}
|
||||
|
||||
private fun assertDefaultState(event: LoggedComponentStateEvents,
|
||||
name: String,
|
||||
value: Any,
|
||||
type: String,
|
||||
withProject: Boolean,
|
||||
defaultProject: Boolean) {
|
||||
assertThat(event.group.id).isEqualTo("settings")
|
||||
assertThat(event.group.version).isGreaterThan(0)
|
||||
assertThat(event.id).isEqualTo("option")
|
||||
|
||||
var size = 4
|
||||
var size = 5
|
||||
if (withProject) size++
|
||||
if (defaultProject) size++
|
||||
|
||||
assertThat(event.data).hasSize(size)
|
||||
assertThat(event.data["component"]).isEqualTo("MyTestComponent")
|
||||
assertThat(event.data["type"]).isEqualTo(type)
|
||||
assertThat(event.data["name"]).isEqualTo(name)
|
||||
assertThat(event.data["value"]).isEqualTo(value)
|
||||
assertThat(event.data["default"]).isEqualTo(true)
|
||||
@@ -422,4 +500,45 @@ class FeatureUsageSettingsEventsTest {
|
||||
@Attribute("second-bool-value")
|
||||
val secondBoolOption: Boolean = secondBool
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private class ComponentStateWithNumerical(intOpt: Int = 0,
|
||||
longOpt: Long = 0,
|
||||
floatOpt: Float = 0.0F,
|
||||
doubleOpt: Double = 0.0,
|
||||
absIntOpt: Int = 0,
|
||||
absLongOpt: Long = 0,
|
||||
absFloatOpt: Float = 0.0F,
|
||||
absDoubleOpt: Double = 0.0,
|
||||
bool: Boolean = false,
|
||||
str: String = "string-option",
|
||||
list: List<Int> = ArrayList()) : ComponentState(bool, str, list) {
|
||||
@Attribute("int-option")
|
||||
val integerOption: Int = intOpt
|
||||
|
||||
@Attribute("long-option")
|
||||
val longOption: Long = longOpt
|
||||
|
||||
@Attribute("float-option")
|
||||
val floatOption: Float = floatOpt
|
||||
|
||||
@Attribute("double-option")
|
||||
val doubleOption: Double = doubleOpt
|
||||
|
||||
@Attribute("abs-int-option")
|
||||
@field:ReportValue
|
||||
val absIntegerOption: Int = absIntOpt
|
||||
|
||||
@Attribute("abs-long-option")
|
||||
@field:ReportValue
|
||||
val absLongOption: Long = absLongOpt
|
||||
|
||||
@Attribute("abs-float-option")
|
||||
@field:ReportValue
|
||||
val absFloatOption: Float = absFloatOpt
|
||||
|
||||
@Attribute("abs-double-option")
|
||||
@field:ReportValue
|
||||
val absDoubleOption: Double = absDoubleOpt
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.ide.ui
|
||||
|
||||
import com.intellij.openapi.components.BaseState
|
||||
import com.intellij.openapi.components.ReportValue
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.ui.scale.JBUIScale
|
||||
import com.intellij.util.PlatformUtils
|
||||
@@ -34,9 +35,11 @@ class UISettingsState : BaseState() {
|
||||
@Deprecated("", replaceWith = ReplaceWith("NotRoamableUiOptions.fontScale"))
|
||||
var fontScale by property(0f)
|
||||
|
||||
@get:ReportValue
|
||||
@get:OptionTag("RECENT_FILES_LIMIT")
|
||||
var recentFilesLimit by property(50)
|
||||
|
||||
@get:ReportValue
|
||||
@get:OptionTag("RECENT_LOCATIONS_LIMIT")
|
||||
var recentLocationsLimit by property(25)
|
||||
|
||||
@@ -47,6 +50,7 @@ class UISettingsState : BaseState() {
|
||||
@get:OptionTag("CONSOLE_CYCLE_BUFFER_SIZE_KB")
|
||||
var consoleCycleBufferSizeKb by property(1024)
|
||||
|
||||
@get:ReportValue
|
||||
@get:OptionTag("EDITOR_TAB_LIMIT")
|
||||
var editorTabLimit by property(10)
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import com.intellij.internal.statistic.utils.StatisticsUploadAssistant
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
|
||||
class FeatureUsageEventLoggerProvider : StatisticsEventLoggerProvider("FUS", 18) {
|
||||
class FeatureUsageEventLoggerProvider : StatisticsEventLoggerProvider("FUS", 19) {
|
||||
override fun isRecordEnabled(): Boolean {
|
||||
return !ApplicationManager.getApplication().isUnitTestMode &&
|
||||
Registry.`is`("feature.usage.event.log.collect.and.upload") &&
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.components;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that an absolute value of the numerical field should be reported in statistics.
|
||||
* Won't work on objects, string or enum fields.
|
||||
*
|
||||
* Can be used within persistent components if reportStatistics flag is enabled.
|
||||
* @see State#reportStatistic()
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ReportValue {
|
||||
}
|
||||
Reference in New Issue
Block a user