From 2b618f36c280cf267105b73575ca8cac5b3c063e Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Tue, 12 Feb 2019 16:06:52 +0100 Subject: [PATCH 1/6] Add telemetry for 'auto refresh' feature --- core/src/main/java/hudson/Functions.java | 7 ++ .../java/jenkins/telemetry/Telemetry.java | 16 +++ .../jenkins/telemetry/impl/AutoRefresh.java | 101 ++++++++++++++++++ .../impl/AutoRefresh/description.jelly | 5 + 4 files changed, 129 insertions(+) create mode 100644 core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java create mode 100644 core/src/main/resources/jenkins/telemetry/impl/AutoRefresh/description.jelly diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index eb784bb9ce..4d4277d735 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -27,6 +27,7 @@ package hudson; import hudson.model.Slave; import hudson.security.*; +import jenkins.telemetry.impl.AutoRefresh; import jenkins.util.SystemProperties; import hudson.cli.CLICommand; import hudson.console.ConsoleAnnotationDescriptor; @@ -646,6 +647,12 @@ public class Functions { if (refresh) { response.addHeader("Refresh", SystemProperties.getString("hudson.Functions.autoRefreshSeconds", "10")); } + + try { + ExtensionList.lookupSingleton(AutoRefresh.class).recordRequest(request, refresh); + } catch (Exception e) { + // ignore telemetry problems + } } public static boolean isAutoRefresh(HttpServletRequest request) { diff --git a/core/src/main/java/jenkins/telemetry/Telemetry.java b/core/src/main/java/jenkins/telemetry/Telemetry.java index d528f5e9ed..6d0a1501b3 100644 --- a/core/src/main/java/jenkins/telemetry/Telemetry.java +++ b/core/src/main/java/jenkins/telemetry/Telemetry.java @@ -141,6 +141,22 @@ public abstract class Telemetry implements ExtensionPoint { return jenkins == null || !jenkins.isUsageStatisticsCollected(); } + /** + * Returns true iff we're in the time period during which this is supposed to collect data. + * @return true iff we're in the time period during which this is supposed to collect data + * + * @since TODO + */ + public boolean isActivePeriod() { + if (getStart().isAfter(LocalDate.now())) { + return false; + } + if (getEnd().isBefore(LocalDate.now())) { + return false; + } + return true; + } + @Extension public static class TelemetryReporter extends AsyncPeriodicWork { diff --git a/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java new file mode 100644 index 0000000000..9ca458ebc1 --- /dev/null +++ b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java @@ -0,0 +1,101 @@ +/* + * The MIT License + * + * Copyright (c) 2019, Daniel Beck + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package jenkins.telemetry.impl; + +import hudson.Extension; +import jenkins.telemetry.Telemetry; +import net.sf.json.JSONObject; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +import javax.annotation.Nonnull; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.time.LocalDate; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentSkipListMap; + +@Extension +@Restricted(NoExternalUse.class) +public class AutoRefresh extends Telemetry { + + private static final Map> sessionsBySetting = new ConcurrentSkipListMap<>(); + + @Nonnull + @Override + public String getId() { + return AutoRefresh.class.getName(); + } + + @Nonnull + @Override + public String getDisplayName() { + return "Use of auto refresh feature"; + } + + @Nonnull + @Override + public LocalDate getStart() { + return LocalDate.of(2019, 2, 10); + } + + @Nonnull + @Override + public LocalDate getEnd() { + return LocalDate.of(2019, 4, 10); + } + + @Override + public JSONObject createContent() { + if (sessionsBySetting.size() == 0) { + return null; + } + Map> currentSessions = new TreeMap<>(sessionsBySetting); + sessionsBySetting.clear(); + + JSONObject payload = new JSONObject(); + for (Map.Entry> entry : currentSessions.entrySet()) { + payload.put(entry.getKey().toString(), entry.getValue().size()); + } + return payload; + } + + public void recordRequest(HttpServletRequest request, boolean enabled) { + if (Telemetry.isDisabled()) { + return; + } + if (!isActivePeriod()) { + return; + } + HttpSession session = request.getSession(false); + if (session != null) { + String sessionId = session.getId(); + sessionsBySetting.putIfAbsent(enabled, new HashSet<>()); + sessionsBySetting.get(enabled).add(sessionId); + } + } +} diff --git a/core/src/main/resources/jenkins/telemetry/impl/AutoRefresh/description.jelly b/core/src/main/resources/jenkins/telemetry/impl/AutoRefresh/description.jelly new file mode 100644 index 0000000000..0a10e901a7 --- /dev/null +++ b/core/src/main/resources/jenkins/telemetry/impl/AutoRefresh/description.jelly @@ -0,0 +1,5 @@ + + + This trial collects information about the "Auto Refresh" feature to determine whether use of the feature is used enough to not remove it in a future release of Jenkins. + We collect the number of HTTP sessions that have the feature (typically controlled via a cookie) enabled or disabled. + From f8df1cd43206fb89739c6884f7ed341897a1ab80 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sat, 2 Mar 2019 02:58:29 +0100 Subject: [PATCH 2/6] Address review feedback --- core/src/main/java/hudson/Functions.java | 3 ++- .../jenkins/telemetry/impl/AutoRefresh.java | 17 +++++++++++------ .../impl/AutoRefresh/description.jelly | 2 +- .../jenkins/telemetry/impl/Messages.properties | 1 + 4 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 core/src/main/resources/jenkins/telemetry/impl/Messages.properties diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index 4d4277d735..ef5c322973 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -179,6 +179,7 @@ import org.kohsuke.accmod.restrictions.DoNotUse; @SuppressWarnings("rawtypes") public class Functions { private static final AtomicLong iota = new AtomicLong(); + private static Logger LOGGER = Logger.getLogger(Functions.class.getName()); public Functions() { } @@ -651,7 +652,7 @@ public class Functions { try { ExtensionList.lookupSingleton(AutoRefresh.class).recordRequest(request, refresh); } catch (Exception e) { - // ignore telemetry problems + LOGGER.log(Level.FINE, "Failed to record auto refresh status in telemetry", e); } } diff --git a/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java index 9ca458ebc1..a641db1ce4 100644 --- a/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java +++ b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java @@ -54,7 +54,7 @@ public class AutoRefresh extends Telemetry { @Nonnull @Override public String getDisplayName() { - return "Use of auto refresh feature"; + return Messages.AutoRefresh_DisplayName(); } @Nonnull @@ -66,7 +66,7 @@ public class AutoRefresh extends Telemetry { @Nonnull @Override public LocalDate getEnd() { - return LocalDate.of(2019, 4, 10); + return LocalDate.of(2019, 5, 31); } @Override @@ -74,8 +74,11 @@ public class AutoRefresh extends Telemetry { if (sessionsBySetting.size() == 0) { return null; } - Map> currentSessions = new TreeMap<>(sessionsBySetting); - sessionsBySetting.clear(); + Map> currentSessions; + synchronized (sessionsBySetting) { + currentSessions = new TreeMap<>(sessionsBySetting); + sessionsBySetting.clear(); + } JSONObject payload = new JSONObject(); for (Map.Entry> entry : currentSessions.entrySet()) { @@ -94,8 +97,10 @@ public class AutoRefresh extends Telemetry { HttpSession session = request.getSession(false); if (session != null) { String sessionId = session.getId(); - sessionsBySetting.putIfAbsent(enabled, new HashSet<>()); - sessionsBySetting.get(enabled).add(sessionId); + synchronized (sessionsBySetting) { + sessionsBySetting.putIfAbsent(enabled, new HashSet<>()); + sessionsBySetting.get(enabled).add(sessionId); + } } } } diff --git a/core/src/main/resources/jenkins/telemetry/impl/AutoRefresh/description.jelly b/core/src/main/resources/jenkins/telemetry/impl/AutoRefresh/description.jelly index 0a10e901a7..e38f0f15cb 100644 --- a/core/src/main/resources/jenkins/telemetry/impl/AutoRefresh/description.jelly +++ b/core/src/main/resources/jenkins/telemetry/impl/AutoRefresh/description.jelly @@ -1,5 +1,5 @@ - This trial collects information about the "Auto Refresh" feature to determine whether use of the feature is used enough to not remove it in a future release of Jenkins. + This trial collects information about the "Auto Refresh" feature to determine whether the feature is used enough to not remove it in a future release of Jenkins. We collect the number of HTTP sessions that have the feature (typically controlled via a cookie) enabled or disabled. diff --git a/core/src/main/resources/jenkins/telemetry/impl/Messages.properties b/core/src/main/resources/jenkins/telemetry/impl/Messages.properties new file mode 100644 index 0000000000..da589e5dba --- /dev/null +++ b/core/src/main/resources/jenkins/telemetry/impl/Messages.properties @@ -0,0 +1 @@ +AutoRefresh.DisplayName = Use of auto refresh feature \ No newline at end of file From a7cccf9d001047eea3fe2f94e9d50790c6468cc5 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sun, 13 Oct 2019 01:29:54 +0200 Subject: [PATCH 3/6] Simpler code --- .../jenkins/telemetry/impl/AutoRefresh.java | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java index a641db1ce4..b9c83a2807 100644 --- a/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java +++ b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java @@ -34,16 +34,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.time.LocalDate; import java.util.HashSet; -import java.util.Map; import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.ConcurrentSkipListMap; +import java.util.Collections; @Extension @Restricted(NoExternalUse.class) public class AutoRefresh extends Telemetry { - private static final Map> sessionsBySetting = new ConcurrentSkipListMap<>(); + private static final Set sessionsWithAutoRefresh = new HashSet<>(); + private static final Set sessionsWithoutAutoRefresh = new HashSet<>(); @Nonnull @Override @@ -60,30 +59,34 @@ public class AutoRefresh extends Telemetry { @Nonnull @Override public LocalDate getStart() { - return LocalDate.of(2019, 2, 10); + return LocalDate.of(2019, 10, 20); } @Nonnull @Override public LocalDate getEnd() { - return LocalDate.of(2019, 5, 31); + return LocalDate.of(2019, 12, 31); } @Override public JSONObject createContent() { - if (sessionsBySetting.size() == 0) { - return null; + int sessionsWithAutoRefreshCount, sessionsWithoutAutoRefreshCount; + synchronized (sessionsWithAutoRefresh) { + sessionsWithAutoRefreshCount = sessionsWithAutoRefresh.size(); + sessionsWithAutoRefresh.clear(); } - Map> currentSessions; - synchronized (sessionsBySetting) { - currentSessions = new TreeMap<>(sessionsBySetting); - sessionsBySetting.clear(); + synchronized (sessionsWithoutAutoRefresh) { + sessionsWithoutAutoRefreshCount = sessionsWithoutAutoRefresh.size(); + sessionsWithoutAutoRefresh.clear(); + } + + if (sessionsWithAutoRefreshCount == 0 && sessionsWithoutAutoRefreshCount == 0) { + return null; } JSONObject payload = new JSONObject(); - for (Map.Entry> entry : currentSessions.entrySet()) { - payload.put(entry.getKey().toString(), entry.getValue().size()); - } + payload.put("enabled", sessionsWithAutoRefreshCount); + payload.put("disabled", sessionsWithoutAutoRefreshCount); return payload; } @@ -97,9 +100,14 @@ public class AutoRefresh extends Telemetry { HttpSession session = request.getSession(false); if (session != null) { String sessionId = session.getId(); - synchronized (sessionsBySetting) { - sessionsBySetting.putIfAbsent(enabled, new HashSet<>()); - sessionsBySetting.get(enabled).add(sessionId); + if (enabled) { + synchronized (sessionsWithAutoRefresh) { + sessionsWithAutoRefresh.add(sessionId); + } + } else { + synchronized (sessionsWithoutAutoRefresh) { + sessionsWithoutAutoRefresh.add(sessionId); + } } } } From 14b9462d00d0a71809ff8ef75d683a4d2a3cc040 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sun, 13 Oct 2019 01:41:16 +0200 Subject: [PATCH 4/6] Increase logging level to be visible --- core/src/main/java/hudson/Functions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index ef5c322973..56c189b7a7 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -652,7 +652,7 @@ public class Functions { try { ExtensionList.lookupSingleton(AutoRefresh.class).recordRequest(request, refresh); } catch (Exception e) { - LOGGER.log(Level.FINE, "Failed to record auto refresh status in telemetry", e); + LOGGER.log(Level.WARNING, "Failed to record auto refresh status in telemetry", e); } } From 50d15406f87112defdc045e574b1fb01b6b2204d Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sun, 13 Oct 2019 01:44:24 +0200 Subject: [PATCH 5/6] Apply code review suggestion, clean up imports --- core/src/main/java/jenkins/telemetry/Telemetry.java | 5 +++-- core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/jenkins/telemetry/Telemetry.java b/core/src/main/java/jenkins/telemetry/Telemetry.java index 6d0a1501b3..bf995bf831 100644 --- a/core/src/main/java/jenkins/telemetry/Telemetry.java +++ b/core/src/main/java/jenkins/telemetry/Telemetry.java @@ -148,10 +148,11 @@ public abstract class Telemetry implements ExtensionPoint { * @since TODO */ public boolean isActivePeriod() { - if (getStart().isAfter(LocalDate.now())) { + LocalDate now = LocalDate.now(); + if (getStart().isAfter(now)) { return false; } - if (getEnd().isBefore(LocalDate.now())) { + if (getEnd().isBefore(now)) { return false; } return true; diff --git a/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java index b9c83a2807..58225b00e2 100644 --- a/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java +++ b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java @@ -35,7 +35,6 @@ import javax.servlet.http.HttpSession; import java.time.LocalDate; import java.util.HashSet; import java.util.Set; -import java.util.Collections; @Extension @Restricted(NoExternalUse.class) From a231b74e2de4ac40286252f99f10ff652e6ae3f3 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Tue, 15 Oct 2019 19:56:12 +0200 Subject: [PATCH 6/6] Address review feedback --- core/src/main/java/jenkins/telemetry/Telemetry.java | 8 +------- .../src/main/java/jenkins/telemetry/impl/AutoRefresh.java | 6 ------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/core/src/main/java/jenkins/telemetry/Telemetry.java b/core/src/main/java/jenkins/telemetry/Telemetry.java index bf995bf831..2817db937d 100644 --- a/core/src/main/java/jenkins/telemetry/Telemetry.java +++ b/core/src/main/java/jenkins/telemetry/Telemetry.java @@ -149,13 +149,7 @@ public abstract class Telemetry implements ExtensionPoint { */ public boolean isActivePeriod() { LocalDate now = LocalDate.now(); - if (getStart().isAfter(now)) { - return false; - } - if (getEnd().isBefore(now)) { - return false; - } - return true; + return now.isAfter(getStart()) && now.isBefore(getEnd()); } @Extension diff --git a/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java index 58225b00e2..cbbe31e3d8 100644 --- a/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java +++ b/core/src/main/java/jenkins/telemetry/impl/AutoRefresh.java @@ -43,12 +43,6 @@ public class AutoRefresh extends Telemetry { private static final Set sessionsWithAutoRefresh = new HashSet<>(); private static final Set sessionsWithoutAutoRefresh = new HashSet<>(); - @Nonnull - @Override - public String getId() { - return AutoRefresh.class.getName(); - } - @Nonnull @Override public String getDisplayName() {