Drop instrumentation-api-caching module and move weak cache implementation to instrumentation-api (#4667)

* Drop instrumentation-api-caching module and move weak cache implementation to instrumentation-api

* Some test fixes

* Some cleanup

* Temporary workaround for using weak values in FutureListenerWrappers

* Spotless

* Update ClassNames and SpanNames

* Compilation and comment

* Add bounded cache and clean interface

* Polish

* Add comment

* Vendor ConcurrentLinkedHashMap in

* Let errorprone ignore vendored CLHM for now

* Keep license in java files too

* Convert Netty wrapper cache to VirtualField

* Work around lambda instrumentation failure

Ideally we would ignore instrumenting helper classes...

* Revert "Work around lambda instrumentation failure"

This reverts commit 6d63815b44.

* Revert "Convert Netty wrapper cache to VirtualField"

This reverts commit dac1522a3f.

* Handle cleared weak values

* Fix comment

* Delete instrumentation-api-caching

* Copy in weak-lock-free

* Remove caffeine remnants

* Fix checkstyle

* Rename BoundedCache to MapBackedCached

* Remove duplicate LICENSE

* Remove outdated comment

* Sync with SDK copy of weaklockfree

* Enable checkstyle:off comment

* Re-generate license report

* Move NOTICE file to package-info.java

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
Nikita Salnikov-Tarnovski 2021-11-24 19:05:12 +02:00 committed by GitHub
parent a5326344bd
commit 821a4b870b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 3757 additions and 1043 deletions

View File

@ -21,7 +21,7 @@ dependencies {
jmh(project(":javaagent-tooling"))
jmh(project(":javaagent-extension-api"))
jmh("com.github.ben-manes.caffeine:caffeine:$caffeine2Version")
jmh("com.github.ben-manes.caffeine:caffeine:2.9.2")
jmh("javax.servlet:javax.servlet-api:4.0.1")
jmh("com.google.http-client:google-http-client:1.19.0")

View File

@ -373,6 +373,8 @@
</module>
<!-- this enables @SuppressWarnings("checkstyle:...") annotations -->
<module name="SuppressWarningsHolder"/>
<!-- this enables CHECKSTYLE:OFF and CHECKSTYLE:ON comments -->
<module name="SuppressionCommentFilter"/>
</module>
<!-- this enables @SuppressWarnings("checkstyle:...") annotations -->
<module name="SuppressWarningsFilter"/>

View File

@ -8,7 +8,6 @@ tasks.withType<ShadowJar>().configureEach {
mergeServiceFiles()
exclude("**/module-info.class")
exclude("META-INF/jandex.idx") // from caffeine
// Prevents conflict with other SLF4J instances. Important for premain.
relocate("org.slf4j", "io.opentelemetry.javaagent.slf4j")

View File

@ -19,7 +19,7 @@ tasks {
disableWarningsInGeneratedCode.set(true)
allDisabledChecksAsWarnings.set(true)
excludedPaths.set(".*/build/generated/.*")
excludedPaths.set(".*/build/generated/.*|.*/concurrentlinkedhashmap/.*")
if (System.getenv("CI") == null) {
disable("SystemOut")

View File

@ -12,8 +12,4 @@ dependencies {
compileOnly("io.opentelemetry:opentelemetry-api")
compileOnly(project(":instrumentation-api"))
compileOnly(project(":javaagent-instrumentation-api"))
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
}

View File

@ -7,10 +7,4 @@ plugins {
extra["mavenGroupId"] = "io.opentelemetry.javaagent.instrumentation"
base.archivesName.set(projectDir.parentFile.name)
dependencies {
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
}
base.archivesName.set(projectDir.parentFile.name)

View File

@ -8,10 +8,4 @@ plugins {
extra["mavenGroupId"] = "io.opentelemetry.instrumentation"
base.archivesName.set(projectDir.parentFile.name)
dependencies {
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
}
base.archivesName.set(projectDir.parentFile.name)

View File

@ -17,9 +17,6 @@ rootProject.extra["otelVersion"] = otelVersion
// Need both BOM and -all
val groovyVersion = "2.5.14"
rootProject.extra["caffeine2Version"] = "2.9.2"
rootProject.extra["caffeine3Version"] = "3.0.4"
// We don't force libraries we instrument to new versions since we compile and test against specific
// old baseline versions
// but we do try to force those libraries' transitive dependencies to new versions where possible
@ -87,7 +84,6 @@ val DEPENDENCY_SETS = listOf(
val DEPENDENCIES = listOf(
"ch.qos.logback:logback-classic:1.2.3",
"com.blogspot.mydailyjava:weak-lock-free:0.18",
"com.github.stefanbirkner:system-lambda:1.2.0",
"com.github.stefanbirkner:system-rules:1.19.0",
"com.google.auto.service:auto-service:1.0",

View File

@ -10,11 +10,6 @@ group = "io.opentelemetry.instrumentation"
dependencies {
implementation(project(":instrumentation-api"))
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
testCompileOnly(project(":instrumentation-api-caching"))
api("io.opentelemetry:opentelemetry-api")
api("io.opentelemetry:opentelemetry-semconv")

View File

@ -5,7 +5,7 @@
package io.opentelemetry.instrumentation.api.annotation.support;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

View File

@ -6,7 +6,7 @@
package io.opentelemetry.instrumentation.api.annotation.support;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
import io.opentelemetry.instrumentation.api.tracer.AttributeSetter;
import java.lang.reflect.Method;

View File

@ -6,7 +6,7 @@
package io.opentelemetry.instrumentation.api.annotation.support
import io.opentelemetry.api.common.AttributesBuilder
import io.opentelemetry.instrumentation.api.caching.Cache
import io.opentelemetry.instrumentation.api.cache.Cache
import spock.lang.Specification
import java.lang.reflect.Method

View File

@ -11,7 +11,7 @@ import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import java.lang.reflect.Method;
import java.util.function.Function;
import org.junit.jupiter.api.Test;

View File

@ -1,44 +0,0 @@
plugins {
id("com.github.johnrengelman.shadow")
id("otel.java-conventions")
}
group = "io.opentelemetry.javaagent"
sourceSets {
main {
val caffeine2ShadedDeps = project(":instrumentation-api-caching:caffeine2")
output.dir(caffeine2ShadedDeps.file("build/extracted/shadow"), "builtBy" to ":instrumentation-api-caching:caffeine2:extractShadowJar")
}
}
val shadowInclude by configurations.creating {
isCanBeResolved = true
isCanBeConsumed = false
}
dependencies {
compileOnly(project(":instrumentation-api-caching:caffeine2", configuration = "shadow"))
compileOnly(project(":instrumentation-api-caching:caffeine3", configuration = "shadow"))
compileOnly("org.checkerframework:checker-qual:3.14.0")
compileOnly("com.blogspot.mydailyjava:weak-lock-free")
shadowInclude("com.blogspot.mydailyjava:weak-lock-free")
}
tasks {
shadowJar {
configurations = listOf(shadowInclude)
relocate("com.blogspot.mydailyjava.weaklockfree", "io.opentelemetry.instrumentation.api.internal.shaded.weaklockfree")
}
val extractShadowJar by registering(Copy::class) {
dependsOn(shadowJar)
from(zipTree(shadowJar.get().archiveFile)) {
exclude("META-INF/**")
}
into("build/extracted/shadow")
}
}

View File

@ -1,58 +0,0 @@
plugins {
id("com.github.johnrengelman.shadow")
id("otel.java-conventions")
}
group = "io.opentelemetry.javaagent"
val shadowInclude by configurations.creating {
isCanBeResolved = true
isCanBeConsumed = false
}
val caffeine2Version: String by project
dependencies {
compileOnly("com.github.ben-manes.caffeine:caffeine:$caffeine2Version")
shadowInclude("com.github.ben-manes.caffeine:caffeine:$caffeine2Version") {
exclude("com.google.errorprone", "error_prone_annotations")
exclude("org.checkerframework", "checker-qual")
}
}
// patch inner class from Caffeine to avoid ForkJoinTask from being loaded too early in the javaagent
val patch by sourceSets.creating {
java {}
}
tasks {
shadowJar {
configurations = listOf(shadowInclude)
relocate("com.github.benmanes.caffeine", "io.opentelemetry.instrumentation.api.internal.shaded.caffeine2")
minimize()
}
javadoc {
enabled = false
}
val extractShadowJar by registering(Copy::class) {
dependsOn(shadowJar)
// replace caffeine class with our patched version
from(zipTree(shadowJar.get().archiveFile)) {
exclude("io/opentelemetry/instrumentation/api/internal/shaded/caffeine2/cache/BoundedLocalCache\$PerformCleanupTask.class")
exclude("META-INF/**")
}
from(patch.output) {
include("io/opentelemetry/instrumentation/api/internal/shaded/caffeine2/cache/BoundedLocalCache\$PerformCleanupTask.class")
}
into("build/extracted/shadow")
// prevents empty com/github/benmanes/caffeine/cache path from ending up in instrumentation-api
includeEmptyDirs = false
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package com.github.benmanes.caffeine.cache;
// Caffeine uses reflection to load cache implementations based on parameters specified by a user.
// We use gradle-shadow-plugin to minimize the dependency on Caffeine, but it does not allow
// specifying classes to keep, only artifacts. It's a relatively simple workaround for us to use
// this non-public class to create a static link to the required implementations we use.
final class CacheImplementations {
// Each type of cache has a cache implementation and a node implementation.
// Strong keys, strong values, maximum size
SSMS<?, ?> ssms; // cache
PSMS<?, ?> psms; // node
// Weak keys, strong values, maximum size
WSMS<?, ?> wsms; // cache
FSMS<?, ?> fsms; // node
// Weak keys, weak values
WI<?, ?> wi; // cache
FW<?, ?> fw; // node
private CacheImplementations() {}
}

View File

@ -1,64 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright 2017 Datadog, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright 2014 Ben Manes. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.opentelemetry.instrumentation.api.internal.shaded.caffeine2.cache;
import java.lang.ref.WeakReference;
/** skeleton outer class just for compilation purposes, not included in the final patch. */
abstract class BoundedLocalCache<K, V> {
abstract void performCleanUp(Runnable task);
/** patched to not extend ForkJoinTask as we don't want that class loaded too early. */
static final class PerformCleanupTask implements Runnable {
private static final long serialVersionUID = 1L;
final WeakReference<BoundedLocalCache<?, ?>> reference;
PerformCleanupTask(BoundedLocalCache<?, ?> cache) {
reference = new WeakReference<>(cache);
}
@Override
public void run() {
BoundedLocalCache<?, ?> cache = reference.get();
if (cache != null) {
cache.performCleanUp(/* ignored */ null);
}
}
}
}

View File

@ -1,41 +0,0 @@
plugins {
id("com.github.johnrengelman.shadow")
id("otel.java-conventions")
}
group = "io.opentelemetry.javaagent"
val shadowInclude by configurations.creating {
isCanBeResolved = true
isCanBeConsumed = false
}
val caffeine3Version: String by project
dependencies {
compileOnly("com.github.ben-manes.caffeine:caffeine:$caffeine3Version")
shadowInclude("com.github.ben-manes.caffeine:caffeine:$caffeine3Version") {
exclude("com.google.errorprone", "error_prone_annotations")
exclude("org.checkerframework", "checker-qual")
}
}
// patch inner class from Caffeine to avoid ForkJoinTask from being loaded too early in the javaagent
val patch by sourceSets.creating {
java {}
}
tasks {
shadowJar {
configurations = listOf(shadowInclude)
relocate("com.github.benmanes.caffeine", "io.opentelemetry.instrumentation.api.internal.shaded.caffeine3")
minimize()
}
javadoc {
enabled = false
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package com.github.benmanes.caffeine.cache;
// Caffeine uses reflection to load cache implementations based on parameters specified by a user.
// We use gradle-shadow-plugin to minimize the dependency on Caffeine, but it does not allow
// specifying classes to keep, only artifacts. It's a relatively simple workaround for us to use
// this non-public class to create a static link to the required implementations we use.
final class CacheImplementations {
// Each type of cache has a cache implementation and a node implementation.
// Strong keys, strong values, maximum size
SSMS<?, ?> ssms; // cache
PSMS<?, ?> psms; // node
// Weak keys, strong values, maximum size
WSMS<?, ?> wsms; // cache
FSMS<?, ?> fsms; // node
// Weak keys, weak values
WI<?, ?> wi; // cache
FW<?, ?> fw; // node
private CacheImplementations() {}
}

View File

@ -1,64 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright 2017 Datadog, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright 2014 Ben Manes. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.opentelemetry.instrumentation.api.internal.shaded.caffeine3.cache;
import java.lang.ref.WeakReference;
/** skeleton outer class just for compilation purposes, not included in the final patch. */
abstract class BoundedLocalCache<K, V> {
abstract void performCleanUp(Runnable task);
/** patched to not extend ForkJoinTask as we don't want that class loaded too early. */
static final class PerformCleanupTask implements Runnable {
private static final long serialVersionUID = 1L;
final WeakReference<BoundedLocalCache<?, ?>> reference;
PerformCleanupTask(BoundedLocalCache<?, ?> cache) {
reference = new WeakReference<>(cache);
}
@Override
public void run() {
BoundedLocalCache<?, ?> cache = reference.get();
if (cache != null) {
cache.performCleanUp(/* ignored */ null);
}
}
}
}

View File

@ -1,74 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.caching;
import java.util.concurrent.Executor;
import javax.annotation.Nullable;
/** A builder of {@link Cache}. */
public final class CacheBuilder {
private static final long UNSET = -1;
private static final boolean USE_CAFFEINE_3 = Caffeine3Cache.available();
private boolean weakKeys;
private boolean weakValues;
private long maximumSize = UNSET;
@Nullable private Executor executor = null;
/** Sets the maximum size of the cache. */
public CacheBuilder setMaximumSize(long maximumSize) {
this.maximumSize = maximumSize;
return this;
}
/**
* Sets that keys should be referenced weakly. If used, keys will use identity comparison, not
* {@link Object#equals(Object)}.
*/
public CacheBuilder setWeakKeys() {
this.weakKeys = true;
return this;
}
/** Sets that values should be referenced weakly. */
public CacheBuilder setWeakValues() {
this.weakValues = true;
return this;
}
// Visible for testing
CacheBuilder setExecutor(Executor executor) {
this.executor = executor;
return this;
}
/** Returns a new {@link Cache} with the settings of this {@link CacheBuilder}. */
public <K, V> Cache<K, V> build() {
if (weakKeys && !weakValues && maximumSize == UNSET) {
return new WeakLockFreeCache<>();
}
CaffeineCache.Builder<K, V> caffeine =
USE_CAFFEINE_3 ? new Caffeine3Cache.Builder<>() : new Caffeine2Cache.Builder<>();
if (weakKeys) {
caffeine.weakKeys();
}
if (weakValues) {
caffeine.weakValues();
}
if (maximumSize != UNSET) {
caffeine.maximumSize(maximumSize);
}
if (executor != null) {
caffeine.executor(executor);
} else {
caffeine.executor(Runnable::run);
}
return caffeine.build();
}
CacheBuilder() {}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.caching;
import io.opentelemetry.instrumentation.api.internal.shaded.caffeine2.cache.Caffeine;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Function;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
final class Caffeine2Cache<K, V> implements CaffeineCache<K, V> {
private final io.opentelemetry.instrumentation.api.internal.shaded.caffeine2.cache.Cache<K, V>
delegate;
Caffeine2Cache(
io.opentelemetry.instrumentation.api.internal.shaded.caffeine2.cache.Cache<K, V> delegate) {
this.delegate = delegate;
}
@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
return delegate.get(key, mappingFunction);
}
@Override
public V get(K key) {
return delegate.getIfPresent(key);
}
@Override
public void put(K key, V value) {
delegate.put(key, value);
}
@Override
public void remove(K key) {
delegate.invalidate(key);
}
// Visible for testing
@Override
public Set<K> keySet() {
return delegate.asMap().keySet();
}
// Visible for testing
@Override
public void cleanup() {
delegate.cleanUp();
}
static class Builder<K, V> implements CaffeineCache.Builder<K, V> {
private final Caffeine<?, ?> caffeine = Caffeine.newBuilder();
@Override
public void weakKeys() {
caffeine.weakKeys();
}
@Override
public void weakValues() {
caffeine.weakValues();
}
@Override
public void maximumSize(@Nonnegative long maximumSize) {
caffeine.maximumSize(maximumSize);
}
@Override
public void executor(@Nonnull Executor executor) {
caffeine.executor(executor);
}
@Override
public Cache<K, V> build() {
@SuppressWarnings("unchecked")
io.opentelemetry.instrumentation.api.internal.shaded.caffeine2.cache.Cache<K, V> delegate =
(io.opentelemetry.instrumentation.api.internal.shaded.caffeine2.cache.Cache<K, V>)
caffeine.build();
return new Caffeine2Cache<>(delegate);
}
}
}

View File

@ -1,99 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.caching;
import io.opentelemetry.instrumentation.api.internal.shaded.caffeine3.cache.Caffeine;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Function;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
final class Caffeine3Cache<K, V> implements CaffeineCache<K, V> {
private final io.opentelemetry.instrumentation.api.internal.shaded.caffeine3.cache.Cache<K, V>
delegate;
Caffeine3Cache(
io.opentelemetry.instrumentation.api.internal.shaded.caffeine3.cache.Cache<K, V> delegate) {
this.delegate = delegate;
}
public static boolean available() {
try {
Caffeine.class.getName();
return true;
} catch (UnsupportedClassVersionError | NoClassDefFoundError exception) {
// caffeine 3 requires jdk 11
return false;
}
}
@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
return delegate.get(key, mappingFunction);
}
@Override
public V get(K key) {
return delegate.getIfPresent(key);
}
@Override
public void put(K key, V value) {
delegate.put(key, value);
}
@Override
public void remove(K key) {
delegate.invalidate(key);
}
// Visible for testing
@Override
public Set<K> keySet() {
return delegate.asMap().keySet();
}
// Visible for testing
@Override
public void cleanup() {
delegate.cleanUp();
}
static class Builder<K, V> implements CaffeineCache.Builder<K, V> {
private final Caffeine<?, ?> caffeine = Caffeine.newBuilder();
@Override
public void weakKeys() {
caffeine.weakKeys();
}
@Override
public void weakValues() {
caffeine.weakValues();
}
@Override
public void maximumSize(@Nonnegative long maximumSize) {
caffeine.maximumSize(maximumSize);
}
@Override
public void executor(@Nonnull Executor executor) {
caffeine.executor(executor);
}
@Override
public Cache<K, V> build() {
@SuppressWarnings("unchecked")
io.opentelemetry.instrumentation.api.internal.shaded.caffeine3.cache.Cache<K, V> delegate =
(io.opentelemetry.instrumentation.api.internal.shaded.caffeine3.cache.Cache<K, V>)
caffeine.build();
return new Caffeine3Cache<>(delegate);
}
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.caching;
import java.util.Set;
import java.util.concurrent.Executor;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
interface CaffeineCache<K, V> extends Cache<K, V> {
interface Builder<K, V> {
void weakKeys();
void weakValues();
void maximumSize(@Nonnegative long maximumSize);
void executor(@Nonnull Executor executor);
Cache<K, V> build();
}
// Visible for testing
Set<K> keySet();
// Visible for testing
void cleanup();
}

View File

@ -1 +0,0 @@
Tests for this module are in the instrumentation-api project to verify against the shaded artifact.

View File

@ -14,17 +14,12 @@ sourceSets {
// set to generate into. By default it would be the src/main directory itself.
srcDir("$buildDir/generated/sources/jflex")
}
val cachingShadedDeps = project(":instrumentation-api-caching")
output.dir(cachingShadedDeps.file("build/extracted/shadow"), "builtBy" to ":instrumentation-api-caching:extractShadowJar")
}
}
group = "io.opentelemetry.instrumentation"
dependencies {
compileOnly(project(":instrumentation-api-caching"))
api("io.opentelemetry:opentelemetry-api")
api("io.opentelemetry:opentelemetry-semconv")
@ -34,7 +29,6 @@ dependencies {
compileOnly("com.google.auto.value:auto-value-annotations")
annotationProcessor("com.google.auto.value:auto-value")
testCompileOnly(project(":instrumentation-api-caching"))
testImplementation(project(":testing-common"))
testImplementation("org.mockito:mockito-core")
testImplementation("org.mockito:mockito-junit-jupiter")
@ -45,6 +39,10 @@ dependencies {
}
tasks {
named<Checkstyle>("checkstyleMain") {
exclude("**/concurrentlinkedhashmap/**")
}
sourcesJar {
dependsOn("generateJflex")
}

View File

@ -3,17 +3,34 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.caching;
package io.opentelemetry.instrumentation.api.cache;
import io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import java.util.function.Function;
import javax.annotation.Nullable;
/** A cache from keys to values. */
public interface Cache<K, V> {
/** Returns a new {@link CacheBuilder} to configure a {@link Cache}. */
static CacheBuilder builder() {
return new CacheBuilder();
/**
* Returns new unbounded cache
*
* <p>Keys are referenced weakly and compared using identity comparison, not {@link
* Object#equals(Object)}.
*/
static <K, V> Cache<K, V> weak() {
return new WeakLockFreeCache<>();
}
/**
* Returns new bounded cache.
*
* <p>Both keys and values are strongly referenced.
*/
static <K, V> Cache<K, V> bounded(int capacity) {
ConcurrentLinkedHashMap<K, V> map =
new ConcurrentLinkedHashMap.Builder<K, V>().maximumWeightedCapacity(capacity).build();
return new MapBackedCache<>(map);
}
/**

View File

@ -0,0 +1,45 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.cache;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import javax.annotation.Nullable;
final class MapBackedCache<K, V> implements Cache<K, V> {
private final ConcurrentMap<K, V> delegate;
MapBackedCache(ConcurrentMap<K, V> delegate) {
this.delegate = delegate;
}
@Override
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
return delegate.computeIfAbsent(key, mappingFunction);
}
@Nullable
@Override
public V get(K key) {
return delegate.get(key);
}
@Override
public void put(K key, V value) {
delegate.put(key, value);
}
@Override
public void remove(K key) {
delegate.remove(key);
}
// Visible for tests
int size() {
return delegate.size();
}
}

View File

@ -3,9 +3,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.caching;
package io.opentelemetry.instrumentation.api.cache;
import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap;
import io.opentelemetry.instrumentation.api.cache.weaklockfree.WeakConcurrentMap;
import java.util.function.Function;
final class WeakLockFreeCache<K, V> implements Cache<K, V> {

View File

@ -0,0 +1,47 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap;
import javax.annotation.concurrent.ThreadSafe;
/**
* A class that can determine the weight of an entry. The total weight threshold is used to
* determine when an eviction is required.
*
* @author ben.manes@gmail.com (Ben Manes)
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
* http://code.google.com/p/concurrentlinkedhashmap/</a>
*/
@ThreadSafe
public interface EntryWeigher<K, V> {
/**
* Measures an entry's weight to determine how many units of capacity that the key and value
* consumes. An entry must consume a minimum of one unit.
*
* @param key the key to weigh
* @param value the value to weigh
* @return the entry's weight
*/
int weightOf(K key, V value);
}

View File

@ -0,0 +1,53 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright 2010 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap;
import javax.annotation.concurrent.ThreadSafe;
/**
* A listener registered for notification when an entry is evicted. An instance may be called
* concurrently by multiple threads to process entries. An implementation should avoid performing
* blocking calls or synchronizing on shared resources.
*
* <p>The listener is invoked by {@link ConcurrentLinkedHashMap} on a caller's thread and will not
* block other threads from operating on the map. An implementation should be aware that the
* caller's thread will not expect long execution times or failures as a side effect of the listener
* being notified. Execution safety and a fast turn around time can be achieved by performing the
* operation asynchronously, such as by submitting a task to an {@link
* java.util.concurrent.ExecutorService}.
*
* @author ben.manes@gmail.com (Ben Manes)
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
* http://code.google.com/p/concurrentlinkedhashmap/</a>
*/
@ThreadSafe
public interface EvictionListener<K, V> {
/**
* A call-back notification that the entry was evicted.
*
* @param key the entry's key
* @param value the entry's value
*/
void onEviction(K key, V value);
}

View File

@ -0,0 +1,449 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.NoSuchElementException;
import javax.annotation.concurrent.NotThreadSafe;
/**
* Linked list implementation of the {@link Deque} interface where the link pointers are tightly
* integrated with the element. Linked deques have no capacity restrictions; they grow as necessary
* to support usage. They are not thread-safe; in the absence of external synchronization, they do
* not support concurrent access by multiple threads. Null elements are prohibited.
*
* <p>Most <tt>LinkedDeque</tt> operations run in constant time by assuming that the {@link Linked}
* parameter is associated with the deque instance. Any usage that violates this assumption will
* result in non-deterministic behavior.
*
* <p>The iterators returned by this class are <em>not</em> <i>fail-fast</i>: If the deque is
* modified at any time after the iterator is created, the iterator will be in an unknown state.
* Thus, in the face of concurrent modification, the iterator risks arbitrary, non-deterministic
* behavior at an undetermined time in the future.
*
* @author ben.manes@gmail.com (Ben Manes)
* @param <E> the type of elements held in this collection
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
* http://code.google.com/p/concurrentlinkedhashmap/</a>
*/
@NotThreadSafe
final class LinkedDeque<E extends Linked<E>> extends AbstractCollection<E> implements Deque<E> {
// This class provides a doubly-linked list that is optimized for the virtual
// machine. The first and last elements are manipulated instead of a slightly
// more convenient sentinel element to avoid the insertion of null checks with
// NullPointerException throws in the byte code. The links to a removed
// element are cleared to help a generational garbage collector if the
// discarded elements inhabit more than one generation.
/** Pointer to first node. Invariant: (first == null && last == null) || (first.prev == null) */
E first;
/** Pointer to last node. Invariant: (first == null && last == null) || (last.next == null) */
E last;
/**
* Links the element to the front of the deque so that it becomes the first element.
*
* @param e the unlinked element
*/
void linkFirst(final E e) {
final E f = first;
first = e;
if (f == null) {
last = e;
} else {
f.setPrevious(e);
e.setNext(f);
}
}
/**
* Links the element to the back of the deque so that it becomes the last element.
*
* @param e the unlinked element
*/
void linkLast(final E e) {
final E l = last;
last = e;
if (l == null) {
first = e;
} else {
l.setNext(e);
e.setPrevious(l);
}
}
/** Unlinks the non-null first element. */
E unlinkFirst() {
final E f = first;
final E next = f.getNext();
f.setNext(null);
first = next;
if (next == null) {
last = null;
} else {
next.setPrevious(null);
}
return f;
}
/** Unlinks the non-null last element. */
E unlinkLast() {
final E l = last;
final E prev = l.getPrevious();
l.setPrevious(null);
last = prev;
if (prev == null) {
first = null;
} else {
prev.setNext(null);
}
return l;
}
/** Unlinks the non-null element. */
void unlink(E e) {
final E prev = e.getPrevious();
final E next = e.getNext();
if (prev == null) {
first = next;
} else {
prev.setNext(next);
e.setPrevious(null);
}
if (next == null) {
last = prev;
} else {
next.setPrevious(prev);
e.setNext(null);
}
}
@Override
public boolean isEmpty() {
return (first == null);
}
void checkNotEmpty() {
if (isEmpty()) {
throw new NoSuchElementException();
}
}
/**
* {@inheritDoc}
*
* <p>Beware that, unlike in most collections, this method is <em>NOT</em> a constant-time
* operation.
*/
@Override
public int size() {
int size = 0;
for (E e = first; e != null; e = e.getNext()) {
size++;
}
return size;
}
@Override
public void clear() {
for (E e = first; e != null; ) {
E next = e.getNext();
e.setPrevious(null);
e.setNext(null);
e = next;
}
first = last = null;
}
@Override
public boolean contains(Object o) {
return (o instanceof Linked<?>) && contains((Linked<?>) o);
}
// A fast-path containment check
boolean contains(Linked<?> e) {
return (e.getPrevious() != null) || (e.getNext() != null) || (e == first);
}
/**
* Moves the element to the front of the deque so that it becomes the first element.
*
* @param e the linked element
*/
public void moveToFront(E e) {
if (e != first) {
unlink(e);
linkFirst(e);
}
}
/**
* Moves the element to the back of the deque so that it becomes the last element.
*
* @param e the linked element
*/
public void moveToBack(E e) {
if (e != last) {
unlink(e);
linkLast(e);
}
}
@Override
public E peek() {
return peekFirst();
}
@Override
public E peekFirst() {
return first;
}
@Override
public E peekLast() {
return last;
}
@Override
public E getFirst() {
checkNotEmpty();
return peekFirst();
}
@Override
public E getLast() {
checkNotEmpty();
return peekLast();
}
@Override
public E element() {
return getFirst();
}
@Override
public boolean offer(E e) {
return offerLast(e);
}
@Override
public boolean offerFirst(E e) {
if (contains(e)) {
return false;
}
linkFirst(e);
return true;
}
@Override
public boolean offerLast(E e) {
if (contains(e)) {
return false;
}
linkLast(e);
return true;
}
@Override
public boolean add(E e) {
return offerLast(e);
}
@Override
public void addFirst(E e) {
if (!offerFirst(e)) {
throw new IllegalArgumentException();
}
}
@Override
public void addLast(E e) {
if (!offerLast(e)) {
throw new IllegalArgumentException();
}
}
@Override
public E poll() {
return pollFirst();
}
@Override
public E pollFirst() {
return isEmpty() ? null : unlinkFirst();
}
@Override
public E pollLast() {
return isEmpty() ? null : unlinkLast();
}
@Override
public E remove() {
return removeFirst();
}
@Override
@SuppressWarnings("unchecked")
public boolean remove(Object o) {
return (o instanceof Linked<?>) && remove((E) o);
}
// A fast-path removal
boolean remove(E e) {
if (contains(e)) {
unlink(e);
return true;
}
return false;
}
@Override
public E removeFirst() {
checkNotEmpty();
return pollFirst();
}
@Override
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}
@Override
public E removeLast() {
checkNotEmpty();
return pollLast();
}
@Override
public boolean removeLastOccurrence(Object o) {
return remove(o);
}
@Override
public boolean removeAll(Collection<?> c) {
boolean modified = false;
for (Object o : c) {
modified |= remove(o);
}
return modified;
}
@Override
public void push(E e) {
addFirst(e);
}
@Override
public E pop() {
return removeFirst();
}
@Override
public Iterator<E> iterator() {
return new AbstractLinkedIterator(first) {
@Override
E computeNext() {
return cursor.getNext();
}
};
}
@Override
public Iterator<E> descendingIterator() {
return new AbstractLinkedIterator(last) {
@Override
E computeNext() {
return cursor.getPrevious();
}
};
}
abstract class AbstractLinkedIterator implements Iterator<E> {
E cursor;
/**
* Creates an iterator that can can traverse the deque.
*
* @param start the initial element to begin traversal from
*/
AbstractLinkedIterator(E start) {
cursor = start;
}
@Override
public boolean hasNext() {
return (cursor != null);
}
@Override
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
E e = cursor;
cursor = computeNext();
return e;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
/** Retrieves the next element to traverse to or <tt>null</tt> if there are no more elements. */
abstract E computeNext();
}
}
/** An element that is linked on the {@link Deque}. */
interface Linked<T extends Linked<T>> {
/**
* Retrieves the previous element or <tt>null</tt> if either the element is unlinked or the first
* element on the deque.
*/
T getPrevious();
/** Sets the previous element or <tt>null</tt> if there is no link. */
void setPrevious(T prev);
/**
* Retrieves the next element or <tt>null</tt> if either the element is unlinked or the last
* element on the deque.
*/
T getNext();
/** Sets the next element or <tt>null</tt> if there is no link. */
void setNext(T next);
}

View File

@ -0,0 +1,46 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright 2010 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap;
import javax.annotation.concurrent.ThreadSafe;
/**
* A class that can determine the weight of a value. The total weight threshold is used to determine
* when an eviction is required.
*
* @author ben.manes@gmail.com (Ben Manes)
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
* http://code.google.com/p/concurrentlinkedhashmap/</a>
*/
@ThreadSafe
public interface Weigher<V> {
/**
* Measures an object's weight to determine how many units of capacity that the value consumes. A
* value must consume a minimum of one unit.
*
* @param value the object to weigh
* @return the object's weight
*/
int weightOf(V value);
}

View File

@ -0,0 +1,280 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright 2010 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap;
import static io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap.ConcurrentLinkedHashMap.checkNotNull;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* A common set of {@link Weigher} and {@link EntryWeigher} implementations.
*
* @author ben.manes@gmail.com (Ben Manes)
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
* http://code.google.com/p/concurrentlinkedhashmap/</a>
*/
public final class Weighers {
private Weighers() {
throw new AssertionError();
}
/**
* A entry weigher backed by the specified weigher. The weight of the value determines the weight
* of the entry.
*
* @param weigher the weigher to be "wrapped" in a entry weigher.
* @return A entry weigher view of the specified weigher.
*/
public static <K, V> EntryWeigher<K, V> asEntryWeigher(final Weigher<? super V> weigher) {
return (weigher == singleton())
? Weighers.<K, V>entrySingleton()
: new EntryWeigherView<>(weigher);
}
/**
* A weigher where an entry has a weight of <tt>1</tt>. A map bounded with this weigher will evict
* when the number of key-value pairs exceeds the capacity.
*
* @return A weigher where a value takes one unit of capacity.
*/
@SuppressWarnings({"cast", "unchecked"})
public static <K, V> EntryWeigher<K, V> entrySingleton() {
return (EntryWeigher<K, V>) SingletonEntryWeigher.INSTANCE;
}
/**
* A weigher where a value has a weight of <tt>1</tt>. A map bounded with this weigher will evict
* when the number of key-value pairs exceeds the capacity.
*
* @return A weigher where a value takes one unit of capacity.
*/
@SuppressWarnings({"cast", "unchecked"})
public static <V> Weigher<V> singleton() {
return (Weigher<V>) SingletonWeigher.INSTANCE;
}
/**
* A weigher where the value is a byte array and its weight is the number of bytes. A map bounded
* with this weigher will evict when the number of bytes exceeds the capacity rather than the
* number of key-value pairs in the map. This allows for restricting the capacity based on the
* memory-consumption and is primarily for usage by dedicated caching servers that hold the
* serialized data.
*
* <p>A value with a weight of <tt>0</tt> will be rejected by the map. If a value with this weight
* can occur then the caller should eagerly evaluate the value and treat it as a removal
* operation. Alternatively, a custom weigher may be specified on the map to assign an empty value
* a positive weight.
*
* @return A weigher where each byte takes one unit of capacity.
*/
public static Weigher<byte[]> byteArray() {
return ByteArrayWeigher.INSTANCE;
}
/**
* A weigher where the value is a {@link Iterable} and its weight is the number of elements. This
* weigher only should be used when the alternative {@link #collection()} weigher cannot be, as
* evaluation takes O(n) time. A map bounded with this weigher will evict when the total number of
* elements exceeds the capacity rather than the number of key-value pairs in the map.
*
* <p>A value with a weight of <tt>0</tt> will be rejected by the map. If a value with this weight
* can occur then the caller should eagerly evaluate the value and treat it as a removal
* operation. Alternatively, a custom weigher may be specified on the map to assign an empty value
* a positive weight.
*
* @return A weigher where each element takes one unit of capacity.
*/
@SuppressWarnings({"cast", "unchecked"})
public static <E> Weigher<? super Iterable<E>> iterable() {
return (Weigher<Iterable<E>>) (Weigher<?>) IterableWeigher.INSTANCE;
}
/**
* A weigher where the value is a {@link Collection} and its weight is the number of elements. A
* map bounded with this weigher will evict when the total number of elements exceeds the capacity
* rather than the number of key-value pairs in the map.
*
* <p>A value with a weight of <tt>0</tt> will be rejected by the map. If a value with this weight
* can occur then the caller should eagerly evaluate the value and treat it as a removal
* operation. Alternatively, a custom weigher may be specified on the map to assign an empty value
* a positive weight.
*
* @return A weigher where each element takes one unit of capacity.
*/
@SuppressWarnings({"cast", "unchecked"})
public static <E> Weigher<? super Collection<E>> collection() {
return (Weigher<Collection<E>>) (Weigher<?>) CollectionWeigher.INSTANCE;
}
/**
* A weigher where the value is a {@link List} and its weight is the number of elements. A map
* bounded with this weigher will evict when the total number of elements exceeds the capacity
* rather than the number of key-value pairs in the map.
*
* <p>A value with a weight of <tt>0</tt> will be rejected by the map. If a value with this weight
* can occur then the caller should eagerly evaluate the value and treat it as a removal
* operation. Alternatively, a custom weigher may be specified on the map to assign an empty value
* a positive weight.
*
* @return A weigher where each element takes one unit of capacity.
*/
@SuppressWarnings({"cast", "unchecked"})
public static <E> Weigher<? super List<E>> list() {
return (Weigher<List<E>>) (Weigher<?>) ListWeigher.INSTANCE;
}
/**
* A weigher where the value is a {@link Set} and its weight is the number of elements. A map
* bounded with this weigher will evict when the total number of elements exceeds the capacity
* rather than the number of key-value pairs in the map.
*
* <p>A value with a weight of <tt>0</tt> will be rejected by the map. If a value with this weight
* can occur then the caller should eagerly evaluate the value and treat it as a removal
* operation. Alternatively, a custom weigher may be specified on the map to assign an empty value
* a positive weight.
*
* @return A weigher where each element takes one unit of capacity.
*/
@SuppressWarnings({"cast", "unchecked"})
public static <E> Weigher<? super Set<E>> set() {
return (Weigher<Set<E>>) (Weigher<?>) SetWeigher.INSTANCE;
}
/**
* A weigher where the value is a {@link Map} and its weight is the number of entries. A map
* bounded with this weigher will evict when the total number of entries across all values exceeds
* the capacity rather than the number of key-value pairs in the map.
*
* <p>A value with a weight of <tt>0</tt> will be rejected by the map. If a value with this weight
* can occur then the caller should eagerly evaluate the value and treat it as a removal
* operation. Alternatively, a custom weigher may be specified on the map to assign an empty value
* a positive weight.
*
* @return A weigher where each entry takes one unit of capacity.
*/
@SuppressWarnings({"cast", "unchecked"})
public static <A, B> Weigher<? super Map<A, B>> map() {
return (Weigher<Map<A, B>>) (Weigher<?>) MapWeigher.INSTANCE;
}
static final class EntryWeigherView<K, V> implements EntryWeigher<K, V>, Serializable {
static final long serialVersionUID = 1;
final Weigher<? super V> weigher;
EntryWeigherView(Weigher<? super V> weigher) {
checkNotNull(weigher);
this.weigher = weigher;
}
@Override
public int weightOf(K key, V value) {
return weigher.weightOf(value);
}
}
enum SingletonEntryWeigher implements EntryWeigher<Object, Object> {
INSTANCE;
@Override
public int weightOf(Object key, Object value) {
return 1;
}
}
enum SingletonWeigher implements Weigher<Object> {
INSTANCE;
@Override
public int weightOf(Object value) {
return 1;
}
}
enum ByteArrayWeigher implements Weigher<byte[]> {
INSTANCE;
@Override
public int weightOf(byte[] value) {
return value.length;
}
}
enum IterableWeigher implements Weigher<Iterable<?>> {
INSTANCE;
@Override
public int weightOf(Iterable<?> values) {
if (values instanceof Collection<?>) {
return ((Collection<?>) values).size();
}
int size = 0;
for (Iterator<?> i = values.iterator(); i.hasNext(); ) {
i.next();
size++;
}
return size;
}
}
enum CollectionWeigher implements Weigher<Collection<?>> {
INSTANCE;
@Override
public int weightOf(Collection<?> values) {
return values.size();
}
}
enum ListWeigher implements Weigher<List<?>> {
INSTANCE;
@Override
public int weightOf(List<?> values) {
return values.size();
}
}
enum SetWeigher implements Weigher<Set<?>> {
INSTANCE;
@Override
public int weightOf(Set<?> values) {
return values.size();
}
}
enum MapWeigher implements Weigher<Map<?, ?>> {
INSTANCE;
@Override
public int weightOf(Map<?, ?> values) {
return values.size();
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* NOTICE file from https://github.com/ben-manes/concurrentlinkedhashmap/blob/master/NOTICE:
*
* ConcurrentLinkedHashMap
* Copyright 2008, Ben Manes
* Copyright 2010, Google Inc.
*
* Some alternate data structures provided by JSR-166e
* from http://gee.cs.oswego.edu/dl/concurrency-interest/.
* Written by Doug Lea and released as Public Domain.
*/
/**
* This package contains an implementation of a bounded {@link java.util.concurrent.ConcurrentMap}
* data structure.
*
* <p>{@link io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap.Weigher} is a simple
* interface for determining how many units of capacity an entry consumes. Depending on which
* concrete Weigher class is used, an entry may consume a different amount of space within the
* cache. The {@link io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap.Weighers}
* class provides utility methods for obtaining the most common kinds of implementations.
*
* <p>{@link io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap.EvictionListener}
* provides the ability to be notified when an entry is evicted from the map. An eviction occurs
* when the entry was automatically removed due to the map exceeding a capacity threshold. It is not
* called when an entry was explicitly removed.
*
* <p>The {@link
* io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap.ConcurrentLinkedHashMap} class
* supplies an efficient, scalable, thread-safe, bounded map. As with the <tt>Java Collections
* Framework</tt> the "Concurrent" prefix is used to indicate that the map is not governed by a
* single exclusion lock.
*
* @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
* http://code.google.com/p/concurrentlinkedhashmap/</a>
*/
package io.opentelemetry.instrumentation.api.cache.concurrentlinkedhashmap;

View File

@ -0,0 +1,387 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright Rafael Winterhalter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Suppress warnings since this is vendored as-is.
// CHECKSTYLE:OFF
package io.opentelemetry.instrumentation.api.cache.weaklockfree;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* A thread-safe map with weak keys. Entries are based on a key's system hash code and keys are
* considered equal only by reference equality. This class offers an abstract-base implementation
* that allows to override methods. This class does not implement the {@link Map} interface because
* this implementation is incompatible with the map contract. While iterating over a map's entries,
* any key that has not passed iteration is referenced non-weakly.
*
* <p>This class has been copied as is from
* https://github.com/raphw/weak-lock-free/blob/ad0e5e0c04d4a31f9485bf12b89afbc9d75473b3/src/main/java/com/blogspot/mydailyjava/weaklockfree/WeakConcurrentMap.java
*/
// Suppress warnings since this is vendored as-is.
@SuppressWarnings({"MissingSummary", "EqualsBrokenForNull", "FieldMissingNullable"})
abstract class AbstractWeakConcurrentMap<K, V, L> extends ReferenceQueue<K>
implements Runnable, Iterable<Map.Entry<K, V>> {
final ConcurrentMap<WeakKey<K>, V> target;
protected AbstractWeakConcurrentMap() {
this(new ConcurrentHashMap<>());
}
/** @param target ConcurrentMap implementation that this class wraps. */
protected AbstractWeakConcurrentMap(ConcurrentMap<WeakKey<K>, V> target) {
this.target = target;
}
/**
* Override with care as it can cause lookup failures if done incorrectly. The result must have
* the same {@link Object#hashCode()} as the input and be {@link Object#equals(Object) equal to} a
* weak reference of the key. When overriding this, also override {@link #resetLookupKey}.
*/
protected abstract L getLookupKey(K key);
/** Resets any reusable state in the {@linkplain #getLookupKey lookup key}. */
protected abstract void resetLookupKey(L lookupKey);
/**
* @param key The key of the entry.
* @return The value of the entry or the default value if it did not exist.
*/
public V get(K key) {
if (key == null) {
throw new NullPointerException();
}
V value;
L lookupKey = getLookupKey(key);
try {
value = target.get(lookupKey);
} finally {
resetLookupKey(lookupKey);
}
if (value == null) {
value = defaultValue(key);
if (value != null) {
V previousValue = target.putIfAbsent(new WeakKey<>(key, this), value);
if (previousValue != null) {
value = previousValue;
}
}
}
return value;
}
/**
* @param key The key of the entry.
* @return The value of the entry or null if it did not exist.
*/
public V getIfPresent(K key) {
if (key == null) {
throw new NullPointerException();
}
L lookupKey = getLookupKey(key);
try {
return target.get(lookupKey);
} finally {
resetLookupKey(lookupKey);
}
}
/**
* @param key The key of the entry.
* @return {@code true} if the key already defines a value.
*/
public boolean containsKey(K key) {
if (key == null) {
throw new NullPointerException();
}
L lookupKey = getLookupKey(key);
try {
return target.containsKey(lookupKey);
} finally {
resetLookupKey(lookupKey);
}
}
/**
* @param key The key of the entry.
* @param value The value of the entry.
* @return The previous entry or {@code null} if it does not exist.
*/
public V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException();
}
return target.put(new WeakKey<>(key, this), value);
}
/**
* @param key The key of the entry.
* @param value The value of the entry.
* @return The previous entry or {@code null} if it does not exist.
*/
public V putIfAbsent(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException();
}
V previous;
L lookupKey = getLookupKey(key);
try {
previous = target.get(lookupKey);
} finally {
resetLookupKey(lookupKey);
}
return previous == null ? target.putIfAbsent(new WeakKey<>(key, this), value) : previous;
}
/**
* @param key The key of the entry.
* @param value The value of the entry.
* @return The previous entry or {@code null} if it does not exist.
*/
public V putIfProbablyAbsent(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException();
}
return target.putIfAbsent(new WeakKey<>(key, this), value);
}
/**
* @param key The key of the entry.
* @return The removed entry or {@code null} if it does not exist.
*/
public V remove(K key) {
if (key == null) {
throw new NullPointerException();
}
L lookupKey = getLookupKey(key);
try {
return target.remove(lookupKey);
} finally {
resetLookupKey(lookupKey);
}
}
/** Clears the entire map. */
public void clear() {
target.clear();
}
/**
* Creates a default value. There is no guarantee that the requested value will be set as a once
* it is created in case that another thread requests a value for a key concurrently.
*
* @param key The key for which to create a default value.
* @return The default value for a key without value or {@code null} for not defining a default
* value.
*/
protected V defaultValue(K key) {
return null;
}
/** Cleans all unused references. */
public void expungeStaleEntries() {
Reference<?> reference;
while ((reference = poll()) != null) {
target.remove(reference);
}
}
/**
* Returns the approximate size of this map where the returned number is at least as big as the
* actual number of entries.
*
* @return The minimum size of this map.
*/
public int approximateSize() {
return target.size();
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
target.remove(remove());
}
} catch (InterruptedException ignored) {
// do nothing
}
}
@Override
public Iterator<Map.Entry<K, V>> iterator() {
return new EntryIterator(target.entrySet().iterator());
}
@Override
public String toString() {
return target.toString();
}
/*
* Why this works:
* ---------------
*
* Note that this map only supports reference equality for keys and uses system hash codes. Also, for the
* WeakKey instances to function correctly, we are voluntarily breaking the Java API contract for
* hashCode/equals of these instances.
*
* System hash codes are immutable and can therefore be computed prematurely and are stored explicitly
* within the WeakKey instances. This way, we always know the correct hash code of a key and always
* end up in the correct bucket of our target map. This remains true even after the weakly referenced
* key is collected.
*
* If we are looking up the value of the current key via WeakConcurrentMap::get or any other public
* API method, we know that any value associated with this key must still be in the map as the mere
* existence of this key makes it ineligible for garbage collection. Therefore, looking up a value
* using another WeakKey wrapper guarantees a correct result.
*
* If we are looking up the map entry of a WeakKey after polling it from the reference queue, we know
* that the actual key was already collected and calling WeakKey::get returns null for both the polled
* instance and the instance within the map. Since we explicitly stored the identity hash code for the
* referenced value, it is however trivial to identify the correct bucket. From this bucket, the first
* weak key with a null reference is removed. Due to hash collision, we do not know if this entry
* represents the weak key. However, we do know that the reference queue polls at least as many weak
* keys as there are stale map entries within the target map. If no key is ever removed from the map
* explicitly, the reference queue eventually polls exactly as many weak keys as there are stale entries.
*
* Therefore, we can guarantee that there is no memory leak.
*
* It is the responsibility of the actual map implementation to implement a lookup key that is used for
* lookups. The lookup key must supply the same semantics as the weak key with regards to hash code.
* The weak key invokes the latent key's equality method upon evaluation.
*/
public static final class WeakKey<K> extends WeakReference<K> {
private final int hashCode;
WeakKey(K key, ReferenceQueue<? super K> queue) {
super(key, queue);
hashCode = System.identityHashCode(key);
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object other) {
if (other instanceof WeakKey<?>) {
return ((WeakKey<?>) other).get() == get();
} else {
return other.equals(this);
}
}
@Override
public String toString() {
return String.valueOf(get());
}
}
private class EntryIterator implements Iterator<Map.Entry<K, V>> {
private final Iterator<Map.Entry<WeakKey<K>, V>> iterator;
private Map.Entry<WeakKey<K>, V> nextEntry;
private K nextKey;
private EntryIterator(Iterator<Map.Entry<WeakKey<K>, V>> iterator) {
this.iterator = iterator;
findNext();
}
private void findNext() {
while (iterator.hasNext()) {
nextEntry = iterator.next();
nextKey = nextEntry.getKey().get();
if (nextKey != null) {
return;
}
}
nextEntry = null;
nextKey = null;
}
@Override
public boolean hasNext() {
return nextKey != null;
}
@Override
public Map.Entry<K, V> next() {
if (nextKey == null) {
throw new NoSuchElementException();
}
try {
return new SimpleEntry(nextKey, nextEntry);
} finally {
findNext();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
private class SimpleEntry implements Map.Entry<K, V> {
private final K key;
final Map.Entry<WeakKey<K>, V> entry;
private SimpleEntry(K key, Map.Entry<WeakKey<K>, V> entry) {
this.key = key;
this.entry = entry;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return entry.getValue();
}
@Override
public V setValue(V value) {
if (value == null) {
throw new NullPointerException();
}
return entry.setValue(value);
}
}
}

View File

@ -0,0 +1,239 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
// Includes work from:
/*
* Copyright Rafael Winterhalter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Suppress warnings since this is vendored as-is.
// CHECKSTYLE:OFF
package io.opentelemetry.instrumentation.api.cache.weaklockfree;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
/**
* A thread-safe map with weak keys. Entries are based on a key's system hash code and keys are
* considered equal only by reference equality. This class does not implement the {@link
* java.util.Map} interface because this implementation is incompatible with the map contract. While
* iterating over a map's entries, any key that has not passed iteration is referenced non-weakly.
*
* <p>This class has been copied as is from
* https://github.com/raphw/weak-lock-free/blob/ad0e5e0c04d4a31f9485bf12b89afbc9d75473b3/src/main/java/com/blogspot/mydailyjava/weaklockfree/WeakConcurrentMap.java
*/
// Suppress warnings since this is copied as-is.
@SuppressWarnings({
"HashCodeToString",
"MissingSummary",
"UngroupedOverloads",
"ThreadPriorityCheck",
"FieldMissingNullable"
})
public class WeakConcurrentMap<K, V>
extends AbstractWeakConcurrentMap<K, V, WeakConcurrentMap.LookupKey<K>> {
/**
* Lookup keys are cached thread-locally to avoid allocations on lookups. This is beneficial as
* the JIT unfortunately can't reliably replace the {@link LookupKey} allocation with stack
* allocations, even though the {@link LookupKey} does not escape.
*/
private static final ThreadLocal<LookupKey<?>> LOOKUP_KEY_CACHE =
new ThreadLocal<LookupKey<?>>() {
@Override
protected LookupKey<?> initialValue() {
return new LookupKey<>();
}
};
private static final AtomicLong ID = new AtomicLong();
private final Thread thread;
private final boolean reuseKeys;
/** @param cleanerThread {@code true} if a thread should be started that removes stale entries. */
public WeakConcurrentMap(boolean cleanerThread) {
this(cleanerThread, isPersistentClassLoader(LookupKey.class.getClassLoader()));
}
/**
* Checks whether the provided {@link ClassLoader} may be unloaded like a web application class
* loader, for example.
*
* <p>If the class loader can't be unloaded, it is safe to use {@link ThreadLocal}s and to reuse
* the {@link LookupKey}. Otherwise, the use of {@link ThreadLocal}s may lead to class loader
* leaks as it prevents the class loader this class is loaded by to unload.
*
* @param classLoader The class loader to check.
* @return {@code true} if the provided class loader can be unloaded.
*/
private static boolean isPersistentClassLoader(ClassLoader classLoader) {
try {
return classLoader == null // bootstrap class loader
|| classLoader == ClassLoader.getSystemClassLoader()
|| classLoader
== ClassLoader.getSystemClassLoader().getParent(); // ext/platfrom class loader;
} catch (Throwable ignored) {
return false;
}
}
/**
* @param cleanerThread {@code true} if a thread should be started that removes stale entries.
* @param reuseKeys {@code true} if the lookup keys should be reused via a {@link ThreadLocal}.
* Note that setting this to {@code true} may result in class loader leaks. See {@link
* #isPersistentClassLoader(ClassLoader)} for more details.
*/
public WeakConcurrentMap(boolean cleanerThread, boolean reuseKeys) {
this(cleanerThread, reuseKeys, new ConcurrentHashMap<>());
}
/**
* @param cleanerThread {@code true} if a thread should be started that removes stale entries.
* @param reuseKeys {@code true} if the lookup keys should be reused via a {@link ThreadLocal}.
* Note that setting this to {@code true} may result in class loader leaks. See {@link
* #isPersistentClassLoader(ClassLoader)} for more details.
* @param target ConcurrentMap implementation that this class wraps.
*/
public WeakConcurrentMap(
boolean cleanerThread, boolean reuseKeys, ConcurrentMap<WeakKey<K>, V> target) {
super(target);
this.reuseKeys = reuseKeys;
if (cleanerThread) {
thread = new Thread(this);
thread.setName("weak-ref-cleaner-" + ID.getAndIncrement());
thread.setPriority(Thread.MIN_PRIORITY);
thread.setDaemon(true);
thread.start();
} else {
thread = null;
}
}
@Override
@SuppressWarnings("unchecked")
protected LookupKey<K> getLookupKey(K key) {
LookupKey<K> lookupKey;
if (reuseKeys) {
lookupKey = (LookupKey<K>) LOOKUP_KEY_CACHE.get();
} else {
lookupKey = new LookupKey<>();
}
return lookupKey.withValue(key);
}
@Override
protected void resetLookupKey(LookupKey<K> lookupKey) {
lookupKey.reset();
}
/** @return The cleaner thread or {@code null} if no such thread was set. */
public Thread getCleanerThread() {
return thread;
}
/*
* A lookup key must only be used for looking up instances within a map. For this to work, it implements an identical contract for
* hash code and equals as the WeakKey implementation. At the same time, the lookup key implementation does not extend WeakReference
* and avoids the overhead that a weak reference implies.
*/
// can't use AutoClosable/try-with-resources as this project still supports Java 6
static final class LookupKey<K> {
private K key;
private int hashCode;
LookupKey<K> withValue(K key) {
this.key = key;
hashCode = System.identityHashCode(key);
return this;
}
/** Failing to reset a lookup key can lead to memory leaks as the key is strongly referenced. */
void reset() {
key = null;
hashCode = 0;
}
@Override
public boolean equals(Object other) {
if (other instanceof WeakConcurrentMap.LookupKey<?>) {
return ((LookupKey<?>) other).key == key;
} else {
return ((WeakKey<?>) other).get() == key;
}
}
@Override
public int hashCode() {
return hashCode;
}
}
/**
* A {@link WeakConcurrentMap} where stale entries are removed as a side effect of interacting
* with this map.
*/
public static class WithInlinedExpunction<K, V> extends WeakConcurrentMap<K, V> {
public WithInlinedExpunction() {
super(false);
}
@Override
public V get(K key) {
expungeStaleEntries();
return super.get(key);
}
@Override
public boolean containsKey(K key) {
expungeStaleEntries();
return super.containsKey(key);
}
@Override
public V put(K key, V value) {
expungeStaleEntries();
return super.put(key, value);
}
@Override
public V remove(K key) {
expungeStaleEntries();
return super.remove(key);
}
@Override
public Iterator<Map.Entry<K, V>> iterator() {
expungeStaleEntries();
return super.iterator();
}
@Override
public int approximateSize() {
expungeStaleEntries();
return super.approximateSize();
}
}
}

View File

@ -9,7 +9,7 @@ import static io.opentelemetry.instrumentation.api.db.StatementSanitizationConfi
import static io.opentelemetry.instrumentation.api.internal.SupportabilityMetrics.CounterNames.SQL_STATEMENT_SANITIZER_CACHE_MISS;
import com.google.auto.value.AutoValue;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.instrumentation.api.internal.SupportabilityMetrics;
import javax.annotation.Nullable;
@ -21,7 +21,7 @@ public final class SqlStatementSanitizer {
private static final SupportabilityMetrics supportability = SupportabilityMetrics.instance();
private static final Cache<CacheKey, SqlStatementInfo> sqlToStatementInfoCache =
Cache.builder().setMaximumSize(1000).build();
Cache.bounded(1000);
public static SqlStatementInfo sanitize(@Nullable String statement) {
return sanitize(statement, SqlDialect.DEFAULT);

View File

@ -6,15 +6,19 @@
package io.opentelemetry.instrumentation.api.instrumenter.http;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.api.caching.Cache;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
final class HttpHeaderAttributes {
private static final Cache<String, AttributeKey<List<String>>> requestKeysCache =
Cache.builder().setMaximumSize(32).build();
private static final Cache<String, AttributeKey<List<String>>> responseKeysCache =
Cache.builder().setMaximumSize(32).build();
// these are naturally bounded because they only store keys listed in
// otel.instrumentation.http.capture-headers.server.request and
// otel.instrumentation.http.capture-headers.server.response
private static final ConcurrentMap<String, AttributeKey<List<String>>> requestKeysCache =
new ConcurrentHashMap<>();
private static final ConcurrentMap<String, AttributeKey<List<String>>> responseKeysCache =
new ConcurrentHashMap<>();
static AttributeKey<List<String>> requestAttributeKey(String headerName) {
return requestKeysCache.computeIfAbsent(headerName, n -> createKey("request", n));

View File

@ -5,7 +5,7 @@
package io.opentelemetry.instrumentation.api.internal;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import javax.annotation.Nullable;
import org.slf4j.Logger;
@ -40,19 +40,19 @@ public final class RuntimeVirtualFieldSupplier {
private static final class CacheBasedVirtualFieldSupplier implements VirtualFieldSupplier {
private final Cache<Class<?>, Cache<Class<?>, VirtualField<?, ?>>>
ownerToFieldToImplementationMap = Cache.builder().setWeakKeys().build();
ownerToFieldToImplementationMap = Cache.weak();
@Override
public <U extends T, T, F> VirtualField<U, F> find(Class<T> type, Class<F> fieldType) {
return (VirtualField<U, F>)
ownerToFieldToImplementationMap
.computeIfAbsent(type, c -> Cache.builder().setWeakKeys().build())
.computeIfAbsent(type, c -> Cache.weak())
.computeIfAbsent(fieldType, c -> new CacheBasedVirtualField<>());
}
}
private static final class CacheBasedVirtualField<T, F> extends VirtualField<T, F> {
private final Cache<T, F> cache = Cache.builder().setWeakKeys().build();
private final Cache<T, F> cache = Cache.weak();
@Override
@Nullable

View File

@ -5,11 +5,11 @@
package io.opentelemetry.instrumentation.api.tracer;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
public final class ClassNames {
private static final Cache<Class<?>, String> simpleNames = Cache.builder().setWeakKeys().build();
private static final Cache<Class<?>, String> simpleNames = Cache.weak();
/**
* This method is used to generate a simple name based on a given class reference, e.g. for use in

View File

@ -5,7 +5,7 @@
package io.opentelemetry.instrumentation.api.tracer;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.instrumentation.api.util.ClassAndMethod;
import java.lang.reflect.Method;
import java.util.Map;
@ -14,8 +14,7 @@ import javax.annotation.Nullable;
public final class SpanNames {
private static final Cache<Class<?>, Map<String, String>> spanNameCaches =
Cache.builder().setWeakKeys().build();
private static final Cache<Class<?>, Map<String, String>> spanNameCaches = Cache.weak();
/**
* This method is used to generate a span name based on a method. Anonymous classes are named

View File

@ -0,0 +1,78 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.cache;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
class CacheTest {
@Nested
@SuppressWarnings("ClassCanBeStatic")
class StrongKeys {
@Test
void bounded() {
Cache<String, String> cache = Cache.bounded(1);
assertThat(cache.computeIfAbsent("bear", unused -> "roar")).isEqualTo("roar");
cache.remove("bear");
MapBackedCache<?, ?> mapBackedCache = ((MapBackedCache<?, ?>) cache);
assertThat(cache.computeIfAbsent("cat", unused -> "meow")).isEqualTo("meow");
assertThat(mapBackedCache.size()).isEqualTo(1);
assertThat(cache.computeIfAbsent("cat", unused -> "bark")).isEqualTo("meow");
assertThat(mapBackedCache.size()).isEqualTo(1);
cache.put("dog", "bark");
assertThat(cache.get("dog")).isEqualTo("bark");
assertThat(mapBackedCache.size()).isEqualTo(1);
assertThat(cache.computeIfAbsent("cat", unused -> "purr")).isEqualTo("purr");
}
}
@Nested
@SuppressWarnings("ClassCanBeStatic")
class WeakKeys {
@SuppressWarnings("StringOperationCanBeSimplified")
@Test
void unbounded() {
Cache<String, String> cache = Cache.weak();
assertThat(cache.computeIfAbsent("bear", unused -> "roar")).isEqualTo("roar");
cache.remove("bear");
WeakLockFreeCache<?, ?> weakLockFreeCache = ((WeakLockFreeCache<?, ?>) cache);
String cat = new String("cat");
String dog = new String("dog");
assertThat(cache.computeIfAbsent(cat, unused -> "meow")).isEqualTo("meow");
assertThat(weakLockFreeCache.size()).isEqualTo(1);
assertThat(cache.computeIfAbsent(cat, unused -> "bark")).isEqualTo("meow");
assertThat(weakLockFreeCache.size()).isEqualTo(1);
cache.put(dog, "bark");
assertThat(cache.get(dog)).isEqualTo("bark");
assertThat(cache.get(cat)).isEqualTo("meow");
assertThat(cache.get(new String("dog"))).isNull();
assertThat(weakLockFreeCache.size()).isEqualTo(2);
assertThat(cache.computeIfAbsent(cat, unused -> "meow")).isEqualTo("meow");
cat = null;
System.gc();
// Wait for GC to be reflected.
await().untilAsserted(() -> assertThat(weakLockFreeCache.size()).isEqualTo(1));
assertThat(cache.computeIfAbsent(dog, unused -> "bark")).isEqualTo("bark");
dog = null;
System.gc();
// Wait for GC to be reflected.
await().untilAsserted(() -> assertThat(weakLockFreeCache.size()).isEqualTo(0));
}
}
}

View File

@ -1,135 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.caching;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
class CacheTest {
@Nested
@SuppressWarnings("ClassCanBeStatic")
class StrongKeys {
@Test
void unbounded() {
Cache<String, String> cache = Cache.builder().build();
assertThat(cache.computeIfAbsent("bear", unused -> "roar")).isEqualTo("roar");
cache.remove("bear");
CaffeineCache<?, ?> caffeineCache = ((CaffeineCache<?, ?>) cache);
assertThat(cache.computeIfAbsent("cat", unused -> "meow")).isEqualTo("meow");
assertThat(caffeineCache.keySet()).hasSize(1);
assertThat(cache.computeIfAbsent("cat", unused -> "bark")).isEqualTo("meow");
assertThat(caffeineCache.keySet()).hasSize(1);
cache.put("dog", "bark");
assertThat(cache.get("dog")).isEqualTo("bark");
assertThat(cache.get("cat")).isEqualTo("meow");
assertThat(cache.get("bear")).isNull();
assertThat(caffeineCache.keySet()).hasSize(2);
assertThat(cache.computeIfAbsent("cat", unused -> "meow")).isEqualTo("meow");
}
@Test
void bounded() {
Cache<String, String> cache = Cache.builder().setMaximumSize(1).build();
assertThat(cache.computeIfAbsent("bear", unused -> "roar")).isEqualTo("roar");
cache.remove("bear");
CaffeineCache<?, ?> caffeineCache = ((CaffeineCache<?, ?>) cache);
assertThat(cache.computeIfAbsent("cat", unused -> "meow")).isEqualTo("meow");
assertThat(caffeineCache.keySet()).hasSize(1);
assertThat(cache.computeIfAbsent("cat", unused -> "bark")).isEqualTo("meow");
assertThat(caffeineCache.keySet()).hasSize(1);
cache.put("dog", "bark");
assertThat(cache.get("dog")).isEqualTo("bark");
caffeineCache.cleanup();
assertThat(caffeineCache.keySet()).hasSize(1);
assertThat(cache.computeIfAbsent("cat", unused -> "purr")).isEqualTo("purr");
}
}
@Nested
@SuppressWarnings("ClassCanBeStatic")
class WeakKeys {
@Test
void unbounded() {
Cache<String, String> cache = Cache.builder().setWeakKeys().build();
assertThat(cache.computeIfAbsent("bear", unused -> "roar")).isEqualTo("roar");
cache.remove("bear");
WeakLockFreeCache<?, ?> weakLockFreeCache = ((WeakLockFreeCache<?, ?>) cache);
String cat = new String("cat");
String dog = new String("dog");
assertThat(cache.computeIfAbsent(cat, unused -> "meow")).isEqualTo("meow");
assertThat(weakLockFreeCache.size()).isEqualTo(1);
assertThat(cache.computeIfAbsent(cat, unused -> "bark")).isEqualTo("meow");
assertThat(weakLockFreeCache.size()).isEqualTo(1);
cache.put(dog, "bark");
assertThat(cache.get(dog)).isEqualTo("bark");
assertThat(cache.get(cat)).isEqualTo("meow");
assertThat(cache.get(new String("dog"))).isNull();
assertThat(weakLockFreeCache.size()).isEqualTo(2);
assertThat(cache.computeIfAbsent(cat, unused -> "meow")).isEqualTo("meow");
cat = null;
System.gc();
// Wait for GC to be reflected.
await().untilAsserted(() -> assertThat(weakLockFreeCache.size()).isEqualTo(1));
assertThat(cache.computeIfAbsent(dog, unused -> "bark")).isEqualTo("bark");
dog = null;
System.gc();
// Wait for GC to be reflected.
await().untilAsserted(() -> assertThat(weakLockFreeCache.size()).isEqualTo(0));
}
@Test
void bounded() {
Cache<String, String> cache = Cache.builder().setWeakKeys().setMaximumSize(1).build();
assertThat(cache.computeIfAbsent("bear", unused -> "roar")).isEqualTo("roar");
cache.remove("bear");
CaffeineCache<?, ?> caffeineCache = ((CaffeineCache<?, ?>) cache);
String cat = new String("cat");
String dog = new String("dog");
assertThat(cache.computeIfAbsent(cat, unused -> "meow")).isEqualTo("meow");
assertThat(cache.get(cat)).isEqualTo("meow");
assertThat(cache.get(new String("cat"))).isNull();
assertThat(caffeineCache.keySet()).hasSize(1);
assertThat(cache.computeIfAbsent(cat, unused -> "bark")).isEqualTo("meow");
assertThat(caffeineCache.keySet()).hasSize(1);
cache.put(dog, "bark");
assertThat(cache.get(dog)).isEqualTo("bark");
assertThat(cache.get(new String("dog"))).isNull();
caffeineCache.cleanup();
assertThat(caffeineCache.keySet()).hasSize(1);
dog = null;
System.gc();
// Wait for GC to be reflected.
await()
.untilAsserted(
() -> {
caffeineCache.cleanup();
assertThat(caffeineCache.keySet()).isEmpty();
});
}
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.api.caching;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Test;
class PatchCaffeineTest {
@Test
void cleanupNotForkJoinTask() {
AtomicReference<AssertionError> errorRef = new AtomicReference<>();
Cache<String, String> cache =
Cache.builder()
.setExecutor(
task -> {
try {
assertThat(task).isNotInstanceOf(ForkJoinTask.class);
} catch (AssertionError e) {
errorRef.set(e);
}
})
.setMaximumSize(1)
.build();
assertThat(cache.computeIfAbsent("cat", unused -> "meow")).isEqualTo("meow");
assertThat(cache.computeIfAbsent("dog", unused -> "bark")).isEqualTo("bark");
AssertionError error = errorRef.get();
if (error != null) {
throw error;
}
}
}

View File

@ -11,20 +11,25 @@ import io.netty.util.concurrent.GenericProgressiveFutureListener;
import io.netty.util.concurrent.ProgressiveFuture;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import java.lang.ref.WeakReference;
public final class FutureListenerWrappers {
// Instead of VirtualField use Cache with weak keys and weak values to store link between original
// listener and wrapper. VirtualField works fine when wrapper is stored in a field on original
// listener, but when listener class is a lambda instead of field it gets stored in a map with
// weak keys where original listener is key and wrapper is value. As wrapper has a strong
// reference to original listener this causes a memory leak.
// Also note that it's ok if the value is collected prior to the key, since this cache is only
// used to remove the wrapped listener from the netty future, and if the value is collected prior
// to the key, that means it's no longer used (referenced) by the netty future anyways.
// note: it's ok if the value is collected prior to the key, since this cache is only used to
// remove the wrapped listener from the netty future, and if the value is collected prior to the
// key, that means it's no longer used (referenced) by the netty future anyways.
//
// also note: this is not using VirtualField in case this is ever converted to library
// instrumentation, because while the library implementation of VirtualField maintains a weak
// reference to its keys, it maintains a strong reference to its values, and in this particular
// case the wrapper listener (value) has a strong reference to original listener (key), which will
// create a memory leak. which is not a problem in the javaagent's implementation of VirtualField,
// since it injects the value directly into the key as a field, and so the value is only retained
// strongly by the key, and so they can be collected together.
private static final Cache<
GenericFutureListener<? extends Future<?>>, GenericFutureListener<? extends Future<?>>>
wrappers = Cache.builder().setWeakKeys().setWeakValues().build();
GenericFutureListener<? extends Future<?>>,
WeakReference<GenericFutureListener<? extends Future<?>>>>
wrappers = Cache.weak();
private static final ClassValue<Boolean> shouldWrap =
new ClassValue<Boolean>() {
@ -44,21 +49,44 @@ public final class FutureListenerWrappers {
@SuppressWarnings("unchecked")
public static GenericFutureListener<?> wrap(
Context context, GenericFutureListener<? extends Future<?>> delegate) {
return wrappers.computeIfAbsent(
delegate,
key -> {
if (delegate instanceof GenericProgressiveFutureListener) {
return new WrappedProgressiveFutureListener(
context, (GenericProgressiveFutureListener<ProgressiveFuture<?>>) delegate);
} else {
return new WrappedFutureListener(context, (GenericFutureListener<Future<?>>) delegate);
}
});
// note: not using computeIfAbsent because that leaves window where WeakReference can be
// collected before we have a chance to make (and return) a strong reference to the wrapper
WeakReference<GenericFutureListener<? extends Future<?>>> resultReference =
wrappers.get(delegate);
if (resultReference != null) {
GenericFutureListener<? extends Future<?>> wrapper = resultReference.get();
if (wrapper != null) {
return wrapper;
}
// note that it's ok if the value is collected prior to the key, since this cache is only
// used to remove the wrapped listener from the netty future, and if the value is collected
// prior
// to the key, that means it's no longer used (referenced) by the netty future anyways.
}
final GenericFutureListener<? extends Future<?>> wrapper;
if (delegate instanceof GenericProgressiveFutureListener) {
wrapper =
new WrappedProgressiveFutureListener(
context, (GenericProgressiveFutureListener<ProgressiveFuture<?>>) delegate);
} else {
wrapper = new WrappedFutureListener(context, (GenericFutureListener<Future<?>>) delegate);
}
wrappers.put(delegate, new WeakReference<>(wrapper));
return wrapper;
}
public static GenericFutureListener<? extends Future<?>> getWrapper(
GenericFutureListener<? extends Future<?>> delegate) {
GenericFutureListener<? extends Future<?>> wrapper = wrappers.get(delegate);
WeakReference<GenericFutureListener<? extends Future<?>>> wrapperReference =
wrappers.get(delegate);
if (wrapperReference == null) {
return delegate;
}
GenericFutureListener<? extends Future<?>> wrapper = wrapperReference.get();
return wrapper == null ? delegate : wrapper;
}

View File

@ -49,10 +49,6 @@ dependencies {
testImplementation("io.opentelemetry:opentelemetry-exporter-otlp")
testImplementation("io.opentelemetry:opentelemetry-exporter-zipkin")
testImplementation(project(":instrumentation-api-annotation-support"))
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
}
tasks.compileTestJava {

View File

@ -12,8 +12,4 @@ dependencies {
testImplementation(project(":testing-common"))
testImplementation("org.mockito:mockito-core")
testImplementation("org.assertj:assertj-core")
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
}

View File

@ -5,7 +5,7 @@
package io.opentelemetry.javaagent.bootstrap;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -17,8 +17,7 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public final class HelperResources {
private static final Cache<ClassLoader, Map<String, URL>> RESOURCES =
Cache.builder().setWeakKeys().build();
private static final Cache<ClassLoader, Map<String, URL>> RESOURCES = Cache.weak();
/** Registers the {@code payload} to be available to instrumentation at {@code path}. */
public static void register(ClassLoader classLoader, String path, URL url) {

View File

@ -16,8 +16,4 @@ dependencies {
// metrics are unstable, do not expose as api
implementation("io.opentelemetry:opentelemetry-sdk-metrics")
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
}

View File

@ -5,7 +5,7 @@
package io.opentelemetry.javaagent.extension;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import java.lang.instrument.Instrumentation;

View File

@ -5,15 +5,14 @@
package io.opentelemetry.javaagent.extension.matcher;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.javaagent.instrumentation.api.internal.ClassLoaderMatcherCacheHolder;
import io.opentelemetry.javaagent.instrumentation.api.internal.InClassLoaderMatcher;
import net.bytebuddy.matcher.ElementMatcher;
class ClassLoaderHasClassesNamedMatcher extends ElementMatcher.Junction.AbstractBase<ClassLoader> {
private final Cache<ClassLoader, Boolean> cache =
Cache.builder().setWeakKeys().setMaximumSize(25).build();
private final Cache<ClassLoader, Boolean> cache = Cache.weak();
private final String[] resources;

View File

@ -19,8 +19,4 @@ dependencies {
testImplementation("org.mockito:mockito-core")
testImplementation("org.mockito:mockito-junit-jupiter")
testImplementation("org.assertj:assertj-core")
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
}

View File

@ -5,7 +5,7 @@
package io.opentelemetry.javaagent.instrumentation.api.internal;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.instrumentation.api.internal.GuardedBy;
import java.net.URL;
import java.util.ArrayList;

View File

@ -40,10 +40,6 @@ dependencies {
testImplementation("org.assertj:assertj-core")
testImplementation("org.mockito:mockito-core")
testImplementation("org.mockito:mockito-junit-jupiter")
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
}
// Here we only include autoconfigure but don"t include OTLP exporters to ensure they are only in

View File

@ -38,8 +38,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.annotation.Nullable;
@ -86,15 +84,6 @@ public class AgentInstaller {
// internal-proxy instrumentation module after the bytebuddy transformer is set up
Proxy.class.getName();
// caffeine can trigger first access of ForkJoinPool under transform(), which leads ForkJoinPool
// not to get transformed itself.
// loading it early here still allows it to be retransformed as part of agent installation below
ForkJoinPool.class.getName();
// caffeine uses AtomicReferenceArray, ensure it is loaded to avoid ClassCircularityError during
// transform.
AtomicReferenceArray.class.getName();
Integer strictContextStressorMillis = Integer.getInteger(STRICT_CONTEXT_STRESSOR_MILLIS);
if (strictContextStressorMillis != null) {
io.opentelemetry.context.ContextStorage.addWrapper(

View File

@ -9,7 +9,7 @@ import static io.opentelemetry.javaagent.tooling.field.GeneratedVirtualFieldName
import static io.opentelemetry.javaagent.tooling.field.GeneratedVirtualFieldNames.getRealSetterName;
import static io.opentelemetry.javaagent.tooling.field.GeneratedVirtualFieldNames.getVirtualFieldImplementationClassName;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import io.opentelemetry.javaagent.tooling.Utils;
import io.opentelemetry.javaagent.tooling.muzzle.VirtualFieldMappings;
@ -264,7 +264,7 @@ final class VirtualFieldImplementationsGenerator {
@SuppressWarnings({"UnusedMethod", "UnusedVariable", "MethodCanBeStatic"})
static final class VirtualFieldImplementationTemplate extends VirtualField<Object, Object> {
private static final VirtualFieldImplementationTemplate INSTANCE =
new VirtualFieldImplementationTemplate(Cache.builder().setWeakKeys().build());
new VirtualFieldImplementationTemplate(Cache.weak());
private final Cache<Object, Object> map;

View File

@ -5,7 +5,7 @@
package io.opentelemetry.javaagent.tooling.ignore;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.javaagent.bootstrap.PatchLogger;
import io.opentelemetry.javaagent.tooling.util.Trie;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
@ -17,8 +17,7 @@ public class IgnoredClassLoadersMatcher extends ElementMatcher.Junction.Abstract
private static final Logger logger = LoggerFactory.getLogger(IgnoredClassLoadersMatcher.class);
/* Cache of classloader-instance -> (true|false). True = skip instrumentation. False = safe to instrument. */
private static final Cache<ClassLoader, Boolean> skipCache =
Cache.builder().setWeakKeys().build();
private static final Cache<ClassLoader, Boolean> skipCache = Cache.weak();
private final Trie<IgnoreAllow> ignoredClassLoaders;

View File

@ -10,7 +10,7 @@ import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.tooling.HelperInjector;
@ -125,7 +125,7 @@ public final class InstrumentationModuleInstaller {
private static class MuzzleMatcher implements AgentBuilder.RawMatcher {
private final InstrumentationModule instrumentationModule;
private final AtomicBoolean initialized = new AtomicBoolean(false);
private final Cache<ClassLoader, Boolean> matchCache = Cache.builder().setWeakKeys().build();
private final Cache<ClassLoader, Boolean> matchCache = Cache.weak();
private volatile ReferenceMatcher referenceMatcher;
private MuzzleMatcher(InstrumentationModule instrumentationModule) {

View File

@ -55,12 +55,9 @@ val licenseReportDependencies by configurations.creating {
extendsFrom(bootstrapLibs)
}
val caffeine3Version: String by project
dependencies {
bootstrapLibs(project(":instrumentation-api"))
bootstrapLibs(project(":instrumentation-api-annotation-support"))
bootstrapLibs(project(":instrumentation-api-caching:caffeine3", configuration = "shadow"))
bootstrapLibs(project(":javaagent-bootstrap"))
bootstrapLibs(project(":javaagent-instrumentation-api"))
bootstrapLibs("org.slf4j:slf4j-simple")
@ -84,11 +81,9 @@ dependencies {
exporterSlimLibs("io.opentelemetry:opentelemetry-exporter-otlp")
exporterSlimLibs("io.opentelemetry:opentelemetry-exporter-otlp-metrics")
// We only have compileOnly dependencies on these to make sure they don't leak into POMs.
licenseReportDependencies("com.github.ben-manes.caffeine:caffeine:$caffeine3Version") {
isTransitive = false
}
licenseReportDependencies("com.blogspot.mydailyjava:weak-lock-free")
// concurrentlinkedhashmap-lru and weak-lock-free are copied in to the instrumentation-api module
licenseReportDependencies("com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2")
licenseReportDependencies("com.blogspot.mydailyjava:weak-lock-free:0.18")
// TODO ideally this would be :instrumentation instead of :javaagent-tooling
// in case there are dependencies (accidentally) pulled in by instrumentation modules
// but I couldn't get that to work

View File

@ -0,0 +1,17 @@
# Jackson JSON processor
Jackson is a high-performance, Free/Open Source JSON processing library.
It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has
been in development since 2007.
It is currently developed by a community of developers.
## Licensing
Jackson 2.x core and extension components are licensed under Apache License 2.0
To find the details that apply to this artifact see the accompanying LICENSE file.
## Credits
A list of contributors may be found from CREDITS(-2.x) file, which is included
in some artifacts (usually source distributions); but is always available
from the source code management (SCM) system project uses.

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,17 @@
# Jackson JSON processor
Jackson is a high-performance, Free/Open Source JSON processing library.
It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has
been in development since 2007.
It is currently developed by a community of developers.
## Licensing
Jackson 2.x core and extension components are licensed under Apache License 2.0
To find the details that apply to this artifact see the accompanying LICENSE file.
## Credits
A list of contributors may be found from CREDITS(-2.x) file, which is included
in some artifacts (usually source distributions); but is always available
from the source code management (SCM) system project uses.

205
licenses/licenses.md generated
View File

@ -1,7 +1,7 @@
#javaagent
##Dependency License Report
_2021-11-09 12:26:05 EET_
_2021-11-23 20:07:26 PST_
## Apache License, Version 2.0
**1** **Group:** `com.blogspot.mydailyjava` **Name:** `weak-lock-free` **Version:** `0.18`
@ -14,133 +14,130 @@ _2021-11-09 12:26:05 EET_
> - **POM Project URL**: [https://github.com/raphw/weak-lock-free](https://github.com/raphw/weak-lock-free)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**3** **Group:** `com.github.ben-manes.caffeine` **Name:** `caffeine` **Version:** `3.0.4`
**3** **Group:** `com.fasterxml.jackson.core` **Name:** `jackson-annotations` **Version:** `2.12.3`
> - **Project URL**: [http://github.com/FasterXML/jackson](http://github.com/FasterXML/jackson)
> - **Manifest License**: Apache License, Version 2.0 (Not Packaged)
> - **POM Project URL**: [https://github.com/ben-manes/caffeine](https://github.com/ben-manes/caffeine)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
> - **Embedded license files**: [caffeine-3.0.4.jar/META-INF/LICENSE](caffeine-3.0.4.jar/META-INF/LICENSE)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **Embedded license files**: [jackson-annotations-2.12.3.jar/META-INF/LICENSE](jackson-annotations-2.12.3.jar/META-INF/LICENSE)
**4** **Group:** `com.github.ben-manes.caffeine` **Name:** `caffeine` **Version:** `3.0.4`
**4** **Group:** `com.fasterxml.jackson.core` **Name:** `jackson-annotations` **Version:** `2.12.3`
> - **Project URL**: [http://github.com/FasterXML/jackson](http://github.com/FasterXML/jackson)
> - **Manifest License**: Apache License, Version 2.0 (Not Packaged)
> - **POM Project URL**: [https://github.com/ben-manes/caffeine](https://github.com/ben-manes/caffeine)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
> - **Embedded license files**: [caffeine-3.0.4.jar/META-INF/LICENSE](caffeine-3.0.4.jar/META-INF/LICENSE)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **Embedded license files**: [jackson-annotations-2.12.3.jar/META-INF/LICENSE](jackson-annotations-2.12.3.jar/META-INF/LICENSE)
**5** **Group:** `io.opentelemetry` **Name:** `opentelemetry-api` **Version:** `1.7.1`
**5** **Group:** `com.fasterxml.jackson.core` **Name:** `jackson-core` **Version:** `2.12.3`
> - **Project URL**: [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core)
> - **Manifest License**: Apache License, Version 2.0 (Not Packaged)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
> - **Embedded license files**: [jackson-core-2.12.3.jar/META-INF/LICENSE](jackson-core-2.12.3.jar/META-INF/LICENSE)
- [jackson-core-2.12.3.jar/META-INF/NOTICE](jackson-core-2.12.3.jar/META-INF/NOTICE)
**6** **Group:** `com.fasterxml.jackson.core` **Name:** `jackson-core` **Version:** `2.12.3`
> - **Project URL**: [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core)
> - **Manifest License**: Apache License, Version 2.0 (Not Packaged)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
> - **Embedded license files**: [jackson-core-2.12.3.jar/META-INF/LICENSE](jackson-core-2.12.3.jar/META-INF/LICENSE)
- [jackson-core-2.12.3.jar/META-INF/NOTICE](jackson-core-2.12.3.jar/META-INF/NOTICE)
**7** **Group:** `com.fasterxml.jackson.core` **Name:** `jackson-databind` **Version:** `2.12.3`
> - **Project URL**: [http://github.com/FasterXML/jackson](http://github.com/FasterXML/jackson)
> - **Manifest License**: Apache License, Version 2.0 (Not Packaged)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
> - **Embedded license files**: [jackson-databind-2.12.3.jar/META-INF/LICENSE](jackson-databind-2.12.3.jar/META-INF/LICENSE)
- [jackson-databind-2.12.3.jar/META-INF/NOTICE](jackson-databind-2.12.3.jar/META-INF/NOTICE)
**8** **Group:** `com.fasterxml.jackson.core` **Name:** `jackson-databind` **Version:** `2.12.3`
> - **Project URL**: [http://github.com/FasterXML/jackson](http://github.com/FasterXML/jackson)
> - **Manifest License**: Apache License, Version 2.0 (Not Packaged)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
> - **Embedded license files**: [jackson-databind-2.12.3.jar/META-INF/LICENSE](jackson-databind-2.12.3.jar/META-INF/LICENSE)
- [jackson-databind-2.12.3.jar/META-INF/NOTICE](jackson-databind-2.12.3.jar/META-INF/NOTICE)
**9** **Group:** `com.googlecode.concurrentlinkedhashmap` **Name:** `concurrentlinkedhashmap-lru` **Version:** `1.4.2`
> - **Manifest License**: Apache License, Version 2.0 (Not Packaged)
> - **POM Project URL**: [http://code.google.com/p/concurrentlinkedhashmap](http://code.google.com/p/concurrentlinkedhashmap)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**10** **Group:** `com.googlecode.concurrentlinkedhashmap` **Name:** `concurrentlinkedhashmap-lru` **Version:** `1.4.2`
> - **Manifest License**: Apache License, Version 2.0 (Not Packaged)
> - **POM Project URL**: [http://code.google.com/p/concurrentlinkedhashmap](http://code.google.com/p/concurrentlinkedhashmap)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**11** **Group:** `io.opentelemetry` **Name:** `opentelemetry-api` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
**6** **Group:** `io.opentelemetry` **Name:** `opentelemetry-api-metrics` **Version:** `1.7.1-alpha`
**12** **Group:** `io.opentelemetry` **Name:** `opentelemetry-api-metrics` **Version:** `1.9.0-alpha`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
**7** **Group:** `io.opentelemetry` **Name:** `opentelemetry-context` **Version:** `1.7.1`
**13** **Group:** `io.opentelemetry` **Name:** `opentelemetry-context` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
**8** **Group:** `io.opentelemetry` **Name:** `opentelemetry-exporter-logging` **Version:** `1.7.1`
**14** **Group:** `io.opentelemetry` **Name:** `opentelemetry-exporter-logging` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**9** **Group:** `io.opentelemetry` **Name:** `opentelemetry-extension-aws` **Version:** `1.7.1`
**15** **Group:** `io.opentelemetry` **Name:** `opentelemetry-extension-aws` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**10** **Group:** `io.opentelemetry` **Name:** `opentelemetry-extension-kotlin` **Version:** `1.7.1`
**16** **Group:** `io.opentelemetry` **Name:** `opentelemetry-extension-kotlin` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**11** **Group:** `io.opentelemetry` **Name:** `opentelemetry-extension-noop-api` **Version:** `1.7.1-alpha`
**17** **Group:** `io.opentelemetry` **Name:** `opentelemetry-extension-noop-api` **Version:** `1.9.0-alpha`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**12** **Group:** `io.opentelemetry` **Name:** `opentelemetry-extension-trace-propagators` **Version:** `1.7.1`
**18** **Group:** `io.opentelemetry` **Name:** `opentelemetry-extension-trace-propagators` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**13** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk` **Version:** `1.7.1`
**19** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**14** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-common` **Version:** `1.7.1`
**20** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-common` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**15** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-extension-autoconfigure` **Version:** `1.7.1-alpha`
**21** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-extension-autoconfigure` **Version:** `1.9.0-alpha`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**16** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-extension-autoconfigure-spi` **Version:** `1.7.1`
**22** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-extension-autoconfigure-spi` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**17** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-extension-resources` **Version:** `1.7.1`
**23** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-extension-resources` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**18** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-metrics` **Version:** `1.7.1-alpha`
**24** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-logs` **Version:** `1.9.0-alpha`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**19** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-trace` **Version:** `1.7.1`
**25** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-metrics` **Version:** `1.9.0-alpha`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**20** **Group:** `io.opentelemetry` **Name:** `opentelemetry-semconv` **Version:** `1.7.1-alpha`
**26** **Group:** `io.opentelemetry` **Name:** `opentelemetry-sdk-trace` **Version:** `1.9.0`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
**27** **Group:** `io.opentelemetry` **Name:** `opentelemetry-semconv` **Version:** `1.9.0-alpha`
> - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java)
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
**21** **Group:** `net.bytebuddy` **Name:** `byte-buddy-dep` **Version:** `1.11.22`
**28** **Group:** `net.bytebuddy` **Name:** `byte-buddy-dep` **Version:** `1.11.22`
> - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)
> - **Embedded license files**: [byte-buddy-dep-1.11.22.jar/META-INF/LICENSE](byte-buddy-dep-1.11.22.jar/META-INF/LICENSE)
- [byte-buddy-dep-1.11.22.jar/META-INF/NOTICE](byte-buddy-dep-1.11.22.jar/META-INF/NOTICE)
**22** **Group:** `org.ow2.asm` **Name:** `asm` **Version:** `9.2`
> - **Manifest Project URL**: [http://asm.ow2.org](http://asm.ow2.org)
> - **Manifest License**: The 3-Clause BSD License (Not Packaged)
> - **POM Project URL**: [http://asm.ow2.io/](http://asm.ow2.io/)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **POM License**: The 3-Clause BSD License - [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
**23** **Group:** `org.ow2.asm` **Name:** `asm-commons` **Version:** `9.2`
> - **Manifest Project URL**: [http://asm.ow2.org](http://asm.ow2.org)
> - **Manifest License**: The 3-Clause BSD License (Not Packaged)
> - **POM Project URL**: [http://asm.ow2.io/](http://asm.ow2.io/)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **POM License**: The 3-Clause BSD License - [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
## Embedded
**24** **Group:** `opentelemetry-java-instrumentation.instrumentation-api-caching` **Name:** `caffeine3` **Version:** `1.8.0-alpha-SNAPSHOT`
> - **Embedded license files**: [opentelemetry-caffeine3-1.8.0-alpha-SNAPSHOT-all.jar/META-INF/LICENSE](opentelemetry-caffeine3-1.8.0-alpha-SNAPSHOT-all.jar/META-INF/LICENSE)
## MIT License
**25** **Group:** `org.slf4j` **Name:** `slf4j-api` **Version:** `1.7.30`
> - **POM Project URL**: [http://www.slf4j.org](http://www.slf4j.org)
> - **POM License**: MIT License - [https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT)
**26** **Group:** `org.slf4j` **Name:** `slf4j-simple` **Version:** `1.7.30`
> - **POM Project URL**: [http://www.slf4j.org](http://www.slf4j.org)
> - **POM License**: MIT License - [https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT)
## The 3-Clause BSD License
**27** **Group:** `org.ow2.asm` **Name:** `asm` **Version:** `9.2`
> - **Manifest Project URL**: [http://asm.ow2.org](http://asm.ow2.org)
> - **Manifest License**: The 3-Clause BSD License (Not Packaged)
> - **POM Project URL**: [http://asm.ow2.io/](http://asm.ow2.io/)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **POM License**: The 3-Clause BSD License - [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
**28** **Group:** `org.ow2.asm` **Name:** `asm` **Version:** `9.2`
> - **Manifest Project URL**: [http://asm.ow2.org](http://asm.ow2.org)
> - **Manifest License**: The 3-Clause BSD License (Not Packaged)
> - **POM Project URL**: [http://asm.ow2.io/](http://asm.ow2.io/)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **POM License**: The 3-Clause BSD License - [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
**29** **Group:** `org.ow2.asm` **Name:** `asm-commons` **Version:** `9.2`
**29** **Group:** `org.ow2.asm` **Name:** `asm` **Version:** `9.2`
> - **Manifest Project URL**: [http://asm.ow2.org](http://asm.ow2.org)
> - **Manifest License**: The 3-Clause BSD License (Not Packaged)
> - **POM Project URL**: [http://asm.ow2.io/](http://asm.ow2.io/)
@ -154,30 +151,70 @@ _2021-11-09 12:26:05 EET_
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **POM License**: The 3-Clause BSD License - [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
## MIT License
**31** **Group:** `org.slf4j` **Name:** `slf4j-api` **Version:** `1.7.30`
> - **POM Project URL**: [http://www.slf4j.org](http://www.slf4j.org)
> - **POM License**: MIT License - [https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT)
**32** **Group:** `org.slf4j` **Name:** `slf4j-simple` **Version:** `1.7.30`
> - **POM Project URL**: [http://www.slf4j.org](http://www.slf4j.org)
> - **POM License**: MIT License - [https://opensource.org/licenses/MIT](https://opensource.org/licenses/MIT)
## The 3-Clause BSD License
**33** **Group:** `org.ow2.asm` **Name:** `asm` **Version:** `9.2`
> - **Manifest Project URL**: [http://asm.ow2.org](http://asm.ow2.org)
> - **Manifest License**: The 3-Clause BSD License (Not Packaged)
> - **POM Project URL**: [http://asm.ow2.io/](http://asm.ow2.io/)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **POM License**: The 3-Clause BSD License - [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
**34** **Group:** `org.ow2.asm` **Name:** `asm` **Version:** `9.2`
> - **Manifest Project URL**: [http://asm.ow2.org](http://asm.ow2.org)
> - **Manifest License**: The 3-Clause BSD License (Not Packaged)
> - **POM Project URL**: [http://asm.ow2.io/](http://asm.ow2.io/)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **POM License**: The 3-Clause BSD License - [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
**35** **Group:** `org.ow2.asm` **Name:** `asm-commons` **Version:** `9.2`
> - **Manifest Project URL**: [http://asm.ow2.org](http://asm.ow2.org)
> - **Manifest License**: The 3-Clause BSD License (Not Packaged)
> - **POM Project URL**: [http://asm.ow2.io/](http://asm.ow2.io/)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **POM License**: The 3-Clause BSD License - [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
**36** **Group:** `org.ow2.asm` **Name:** `asm-commons` **Version:** `9.2`
> - **Manifest Project URL**: [http://asm.ow2.org](http://asm.ow2.org)
> - **Manifest License**: The 3-Clause BSD License (Not Packaged)
> - **POM Project URL**: [http://asm.ow2.io/](http://asm.ow2.io/)
> - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
> - **POM License**: The 3-Clause BSD License - [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
## Unknown
**31** **Group:** `com.fasterxml.jackson` **Name:** `jackson-bom` **Version:** `2.12.3`
**37** **Group:** `com.fasterxml.jackson` **Name:** `jackson-bom` **Version:** `2.12.3`
**32** **Group:** `com.google.guava` **Name:** `guava-bom` **Version:** `30.1.1-jre`
**38** **Group:** `com.google.guava` **Name:** `guava-bom` **Version:** `30.1.1-jre`
**33** **Group:** `io.opentelemetry` **Name:** `opentelemetry-bom` **Version:** `1.7.1`
**39** **Group:** `io.opentelemetry` **Name:** `opentelemetry-bom` **Version:** `1.9.0`
**34** **Group:** `io.opentelemetry` **Name:** `opentelemetry-bom-alpha` **Version:** `1.7.1-alpha`
**40** **Group:** `io.opentelemetry` **Name:** `opentelemetry-bom-alpha` **Version:** `1.9.0-alpha`
**35** **Group:** `io.opentelemetry.jaxrs-common` **Name:** `bootstrap` **Version:** `1.8.0-alpha-SNAPSHOT`
**41** **Group:** `io.opentelemetry.jaxrs-common` **Name:** `bootstrap` **Version:** `1.9.0-alpha-SNAPSHOT`
**36** **Group:** `io.opentelemetry.kafka-clients-0.11` **Name:** `bootstrap` **Version:** `1.8.0-alpha-SNAPSHOT`
**42** **Group:** `io.opentelemetry.kafka-clients-0.11` **Name:** `bootstrap` **Version:** `1.9.0-alpha-SNAPSHOT`
**37** **Group:** `io.opentelemetry.rmi` **Name:** `bootstrap` **Version:** `1.8.0-alpha-SNAPSHOT`
**43** **Group:** `io.opentelemetry.rmi` **Name:** `bootstrap` **Version:** `1.9.0-alpha-SNAPSHOT`
**38** **Group:** `io.opentelemetry.undertow-1.4` **Name:** `bootstrap` **Version:** `1.8.0-alpha-SNAPSHOT`
**44** **Group:** `io.opentelemetry.undertow-1.4` **Name:** `bootstrap` **Version:** `1.9.0-alpha-SNAPSHOT`
**39** **Group:** `opentelemetry-java-instrumentation` **Name:** `dependencyManagement` **Version:** `1.8.0-alpha-SNAPSHOT`
**45** **Group:** `opentelemetry-java-instrumentation` **Name:** `dependencyManagement` **Version:** `1.9.0-alpha-SNAPSHOT`
**40** **Group:** `org.codehaus.groovy` **Name:** `groovy-bom` **Version:** `2.5.14`
**46** **Group:** `org.codehaus.groovy` **Name:** `groovy-bom` **Version:** `2.5.14`
**41** **Group:** `org.jetbrains.kotlin` **Name:** `kotlin-bom` **Version:** `1.4.10`
**47** **Group:** `org.jetbrains.kotlin` **Name:** `kotlin-bom` **Version:** `1.4.10`
**42** **Group:** `org.junit` **Name:** `junit-bom` **Version:** `5.7.2`
**48** **Group:** `org.junit` **Name:** `junit-bom` **Version:** `5.7.2`

View File

@ -21,10 +21,6 @@ dependencies {
implementation(project(":javaagent-extension-api"))
implementation("org.slf4j:slf4j-api")
// this only exists to make Intellij happy since it doesn't (currently at least) understand our
// inclusion of this artifact inside of :instrumentation-api
compileOnly(project(":instrumentation-api-caching"))
testImplementation(project(":testing-common"))
testImplementation("com.google.guava:guava")
testImplementation("org.assertj:assertj-core:3.19.0")

View File

@ -5,7 +5,7 @@
package io.opentelemetry.javaagent.tooling;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import io.opentelemetry.javaagent.bootstrap.HelperResources;
import io.opentelemetry.javaagent.tooling.muzzle.HelperResource;
import java.io.File;
@ -58,8 +58,7 @@ public class HelperInjector implements Transformer {
}
};
private static final Cache<Class<?>, Boolean> injectedClasses =
Cache.builder().setWeakKeys().build();
private static final Cache<Class<?>, Boolean> injectedClasses = Cache.weak();
private final String requestingName;
@ -69,10 +68,8 @@ public class HelperInjector implements Transformer {
@Nullable private final Instrumentation instrumentation;
private final Map<String, byte[]> dynamicTypeMap = new LinkedHashMap<>();
private final Cache<ClassLoader, Boolean> injectedClassLoaders =
Cache.builder().setWeakKeys().build();
private final Cache<ClassLoader, Boolean> resourcesInjectedClassLoaders =
Cache.builder().setWeakKeys().build();
private final Cache<ClassLoader, Boolean> injectedClassLoaders = Cache.weak();
private final Cache<ClassLoader, Boolean> resourcesInjectedClassLoaders = Cache.weak();
private final List<WeakReference<Object>> helperModules = new CopyOnWriteArrayList<>();

View File

@ -5,7 +5,7 @@
package io.opentelemetry.javaagent.tooling.muzzle;
import io.opentelemetry.instrumentation.api.caching.Cache;
import io.opentelemetry.instrumentation.api.cache.Cache;
import java.lang.ref.WeakReference;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.annotation.AnnotationList;
@ -48,14 +48,13 @@ public class AgentCachingPoolStrategy implements AgentBuilder.PoolStrategy {
* <li>Allow for quick fast path equivalence check of composite keys
* </ul>
*/
final Cache<ClassLoader, WeakReference<ClassLoader>> loaderRefCache =
Cache.builder().setWeakKeys().build();
final Cache<ClassLoader, WeakReference<ClassLoader>> loaderRefCache = Cache.weak();
/**
* Single shared Type.Resolution cache -- uses a composite key -- conceptually of loader & name
*/
final Cache<TypeCacheKey, TypePool.Resolution> sharedResolutionCache =
Cache.builder().setMaximumSize(TYPE_CAPACITY).build();
Cache.bounded(TYPE_CAPACITY);
// fast path for bootstrap
final SharedResolutionCacheAdapter bootstrapCacheProvider =

View File

@ -74,9 +74,6 @@ include(":javaagent")
include(":bom-alpha")
include(":instrumentation-api")
include(":instrumentation-api-caching")
include(":instrumentation-api-caching:caffeine2")
include(":instrumentation-api-caching:caffeine3")
include(":javaagent-instrumentation-api")
include(":instrumentation-api-annotation-support")

View File

@ -10,7 +10,6 @@ import io.opentelemetry.javaagent.tooling.Constants
import org.slf4j.LoggerFactory
import java.util.concurrent.TimeoutException
import spock.util.environment.Jvm
// this test is run using
// -Dotel.javaagent.exclude-classes=config.exclude.packagename.*,config.exclude.SomeClass,config.exclude.SomeClass$NestedClass
@ -22,10 +21,6 @@ class AgentInstrumentationSpecificationTest extends AgentInstrumentationSpecific
setup:
final List<String> bootstrapClassesIncorrectlyLoaded = []
for (ClassPath.ClassInfo info : getTestClasspath().getAllClasses()) {
if (info.getName().toLowerCase().contains("caffeine3") && !Jvm.getCurrent().isJava11Compatible()) {
// caffeine 3 classes are compiled for java 11
continue
}
for (int i = 0; i < Constants.BOOTSTRAP_PACKAGE_PREFIXES.size(); ++i) {
if (info.getName().startsWith(Constants.BOOTSTRAP_PACKAGE_PREFIXES[i])) {
Class<?> bootstrapClass = Class.forName(info.getName())