-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Andre Dietisheim <[email protected]>
- Loading branch information
Showing
25 changed files
with
3,040 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
...java/com/redhat/devtools/intellij/telemetry/core/configuration/limits/Configurations.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2024 Red Hat, Inc. | ||
* Distributed under license by Red Hat, Inc. All rights reserved. | ||
* This program is made available under the terms of the | ||
* Eclipse Public License v2.0 which accompanies this distribution, | ||
* and is available at http://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* Contributors: | ||
* Red Hat, Inc. - initial API and implementation | ||
******************************************************************************/ | ||
package com.redhat.devtools.intellij.telemetry.core.configuration.limits; | ||
|
||
import com.intellij.openapi.diagnostic.Logger; | ||
import com.redhat.devtools.intellij.telemetry.core.util.Directories; | ||
import okhttp3.OkHttpClient; | ||
import okhttp3.Request; | ||
import okhttp3.Response; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.StandardCopyOption; | ||
import java.nio.file.attribute.BasicFileAttributes; | ||
import java.nio.file.attribute.FileTime; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.stream.Collectors; | ||
|
||
class Configurations { | ||
|
||
private static final Logger LOGGER = Logger.getInstance(Configurations.class); | ||
static final Path LOCAL = Directories.RED_HAT.resolve("telemetry-config.json"); | ||
static final String EMBEDDED = "/telemetry-config.json"; | ||
static final String REMOTE = "https://raw.githubusercontent.com/adietish/intellij-redhat-telemetry/issue-82/src/main/resources/telemetry-config.json"; | ||
|
||
private final OkHttpClient client = new OkHttpClient.Builder() | ||
.connectTimeout(5, TimeUnit.SECONDS) | ||
.readTimeout(5, TimeUnit.SECONDS) | ||
.writeTimeout(5, TimeUnit.SECONDS) | ||
.build(); | ||
|
||
public String getRemote() { | ||
return getRemote( | ||
in -> Files.copy(in, LOCAL, StandardCopyOption.REPLACE_EXISTING), | ||
client, | ||
this::getLocal); | ||
} | ||
|
||
/* for testing purposes */ | ||
String getRemote(ThrowingInputStreamConsumer fileWriter, OkHttpClient client, ThrowingSupplier<String, Throwable> fileReader) { | ||
Request request = new Request.Builder() | ||
.url(REMOTE) | ||
.addHeader("Content-Type", "application/json") | ||
.build(); | ||
try (Response response = client.newCall(request).execute()) { | ||
if (response.body() != null) { | ||
fileWriter.accept(response.body().byteStream()); | ||
} | ||
return fileReader.get(); | ||
} catch (Throwable e) { | ||
LOGGER.warn("Could not download remote limits configurations.", e); | ||
return null; | ||
} | ||
} | ||
|
||
/* for testing purposes */ | ||
interface ThrowingInputStreamConsumer { | ||
void accept(InputStream in) throws IOException; | ||
} | ||
|
||
public boolean localExists() { | ||
return Files.exists(LOCAL); | ||
} | ||
|
||
public FileTime getLocalLastModified() { | ||
return getLocalLastModified( | ||
() -> Files.exists(LOCAL), | ||
() -> Files.readAttributes(LOCAL, BasicFileAttributes.class)); | ||
} | ||
|
||
/* for testing purposes */ | ||
FileTime getLocalLastModified(ThrowingSupplier<Boolean, Throwable> exists, ThrowingSupplier<BasicFileAttributes, Throwable> attributesSupplier) { | ||
try { | ||
if (!exists.get()) { | ||
return null; | ||
} | ||
BasicFileAttributes attributes = attributesSupplier.get(); | ||
return attributes.lastModifiedTime(); | ||
} catch (Throwable e) { | ||
return null; | ||
} | ||
} | ||
|
||
interface ThrowingSupplier<T, E extends Throwable> { | ||
T get() throws E; | ||
} | ||
|
||
public String getLocal() { | ||
try { | ||
return toString(Files.newInputStream(LOCAL)); | ||
} catch (IOException e) { | ||
return null; | ||
} | ||
} | ||
|
||
public String getEmbedded() { | ||
return toString(MessageLimits.class.getResourceAsStream(EMBEDDED)); | ||
} | ||
|
||
private String toString(InputStream in) { | ||
if (in == null) { | ||
return null; | ||
} | ||
BufferedReader reader = new BufferedReader(new InputStreamReader(in)); | ||
return reader.lines().collect(Collectors.joining()); | ||
} | ||
|
||
} |
42 changes: 42 additions & 0 deletions
42
src/main/java/com/redhat/devtools/intellij/telemetry/core/configuration/limits/Enabled.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2024 Red Hat, Inc. | ||
* Distributed under license by Red Hat, Inc. All rights reserved. | ||
* This program is made available under the terms of the | ||
* Eclipse Public License v2.0 which accompanies this distribution, | ||
* and is available at http://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* Contributors: | ||
* Red Hat, Inc. - initial API and implementation | ||
******************************************************************************/ | ||
package com.redhat.devtools.intellij.telemetry.core.configuration.limits; | ||
|
||
import com.intellij.openapi.util.text.StringUtil; | ||
|
||
import java.util.Arrays; | ||
|
||
public enum Enabled { | ||
ALL("all"), | ||
ERROR("error"), | ||
CRASH("crash"), | ||
OFF("off"); | ||
|
||
private final String value; | ||
|
||
Enabled(String value) { | ||
this.value = value; | ||
} | ||
|
||
private boolean hasValue(String value) { | ||
if (StringUtil.isEmptyOrSpaces(value)) { | ||
return this.value == null; | ||
} | ||
return value.equals(this.value); | ||
} | ||
|
||
public static Enabled safeValueOf(String value) { | ||
return Arrays.stream(values()) | ||
.filter(instance -> instance.hasValue(value)) | ||
.findAny() | ||
.orElse(ALL); | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
src/main/java/com/redhat/devtools/intellij/telemetry/core/configuration/limits/Filter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2024 Red Hat, Inc. | ||
* Distributed under license by Red Hat, Inc. All rights reserved. | ||
* This program is made available under the terms of the | ||
* Eclipse Public License v2.0 which accompanies this distribution, | ||
* and is available at http://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* Contributors: | ||
* Red Hat, Inc. - initial API and implementation | ||
******************************************************************************/ | ||
package com.redhat.devtools.intellij.telemetry.core.configuration.limits; | ||
|
||
import com.redhat.devtools.intellij.telemetry.core.service.Event; | ||
import com.redhat.devtools.intellij.telemetry.core.util.BasicGlobPattern; | ||
|
||
public interface Filter { | ||
|
||
boolean isMatching(Event event); | ||
|
||
boolean isIncludedByRatio(float percentile); | ||
|
||
boolean isExcludedByRatio(float percentile); | ||
|
||
class EventPropertyFilter implements Filter { | ||
private final String name; | ||
private final BasicGlobPattern glob; | ||
|
||
EventPropertyFilter(String name, String valueGlob) { | ||
this.name = name; | ||
this.glob = BasicGlobPattern.compile(valueGlob); | ||
} | ||
|
||
@Override | ||
public boolean isMatching(Event event) { | ||
String value = event.getProperties().get(name); | ||
return glob.matches(value); | ||
} | ||
|
||
@Override | ||
public boolean isIncludedByRatio(float percentile) { | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean isExcludedByRatio(float percentile) { | ||
return false; | ||
} | ||
|
||
} | ||
|
||
class EventNameFilter implements Filter { | ||
private final BasicGlobPattern name; | ||
private final float ratio; | ||
private final String dailyLimit; | ||
|
||
EventNameFilter(String name, float ratio, String dailyLimit) { | ||
this.name = BasicGlobPattern.compile(name); | ||
this.ratio = ratio; | ||
this.dailyLimit = dailyLimit; | ||
} | ||
|
||
public float getRatio() { | ||
return ratio; | ||
} | ||
|
||
public String getDailyLimit() { | ||
return dailyLimit; | ||
} | ||
|
||
@Override | ||
public boolean isMatching(Event event) { | ||
return name.matches(event.getName()); | ||
} | ||
|
||
@Override | ||
public boolean isIncludedByRatio(float percentile) { | ||
return ratio != 0 | ||
&& percentile <= ratio; | ||
} | ||
|
||
@Override | ||
public boolean isExcludedByRatio(float percentile) { | ||
return 1 - ratio < percentile; | ||
} | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
.../java/com/redhat/devtools/intellij/telemetry/core/configuration/limits/MessageLimits.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2024 Red Hat, Inc. | ||
* Distributed under license by Red Hat, Inc. All rights reserved. | ||
* This program is made available under the terms of the | ||
* Eclipse Public License v2.0 which accompanies this distribution, | ||
* and is available at http://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* Contributors: | ||
* Red Hat, Inc. - initial API and implementation | ||
******************************************************************************/ | ||
package com.redhat.devtools.intellij.telemetry.core.configuration.limits; | ||
|
||
import com.intellij.openapi.util.text.StringUtil; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.attribute.FileTime; | ||
import java.time.Duration; | ||
import java.time.LocalDateTime; | ||
import java.time.ZoneId; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class MessageLimits { | ||
|
||
private static final Duration DEFAULT_REFRESH_PERIOD = Duration.ofHours(6); | ||
private static MessageLimits INSTANCE = null; | ||
private final PluginLimitsFactory factory; | ||
private final Configurations configuration; | ||
private List<PluginLimits> limits; | ||
|
||
static MessageLimits getInstance() { | ||
if (INSTANCE == null) { | ||
INSTANCE = new MessageLimits(PluginLimitsDeserialization::create, new Configurations()); | ||
} | ||
return INSTANCE; | ||
} | ||
|
||
interface PluginLimitsFactory { | ||
List<PluginLimits> create(String json) throws IOException; | ||
} | ||
|
||
MessageLimits(PluginLimitsFactory factory, Configurations configuration) { | ||
this.factory = factory; | ||
this.configuration = configuration; | ||
} | ||
|
||
/** for testing purposes **/ | ||
MessageLimits(List<PluginLimits> limits, PluginLimitsFactory factory, Configurations configuration) { | ||
this(factory,configuration); | ||
this.limits = limits; | ||
} | ||
|
||
List<PluginLimits> get() { | ||
PluginLimits defaultLimits = getDefaultLimits(limits); | ||
Duration refreshAfter = getRefreshAfter(defaultLimits); | ||
FileTime lastModified = configuration.getLocalLastModified(); | ||
if (needsRefresh(refreshAfter, lastModified)) { | ||
this.limits = createLimits(configuration.getRemote(), factory); | ||
} | ||
return limits; | ||
} | ||
|
||
private boolean needsRefresh(Duration refreshAfter, FileTime modified) { | ||
if (modified == null) { | ||
return true; | ||
} | ||
LocalDateTime modificationLocalTime = LocalDateTime.ofInstant(modified.toInstant(), ZoneId.systemDefault()); | ||
LocalDateTime refreshAt = modificationLocalTime.plus(refreshAfter); | ||
return refreshAt.isBefore(LocalDateTime.now()); | ||
} | ||
|
||
@Nullable | ||
private PluginLimits getDefaultLimits(List<PluginLimits> limits) { | ||
if (limits == null) { | ||
return null; | ||
} | ||
return limits.stream() | ||
.filter(PluginLimits::isDefault) | ||
.findAny() | ||
.orElse(null); | ||
} | ||
|
||
private Duration getRefreshAfter(PluginLimits limits) { | ||
if (limits == null | ||
|| limits.getRefresh() == -1) { | ||
return DEFAULT_REFRESH_PERIOD; | ||
} | ||
return Duration.ofHours(limits.getRefresh()); | ||
} | ||
|
||
private List<PluginLimits> createLimits(String config, PluginLimitsFactory factory) { | ||
try { | ||
if (StringUtil.isEmptyOrSpaces(config)) { | ||
return Collections.emptyList(); | ||
} | ||
return factory.create(config); | ||
} catch (IOException e) { | ||
return Collections.emptyList(); | ||
} | ||
} | ||
} |
Oops, something went wrong.