Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime connection string #2809

Merged
merged 21 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ public void trackMetric(
}
}

public static void setConnectionString(String connectionString) {
if (delegate != null) {
delegate.setConnectionString(connectionString);
}
}

public static void trackEvent(
@Nullable Date timestamp,
String name,
Expand Down Expand Up @@ -338,6 +344,8 @@ private BytecodeUtil() {}

public interface BytecodeUtilDelegate {

void setConnectionString(String connectionString);

void trackEvent(
@Nullable Date timestamp,
String name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.azure.monitor.opentelemetry.exporter.implementation.utils.FormattedTime;
import com.azure.monitor.opentelemetry.exporter.implementation.utils.Strings;
import com.microsoft.applicationinsights.agent.bootstrap.BytecodeUtil.BytecodeUtilDelegate;
import com.microsoft.applicationinsights.agent.internal.init.RuntimeConfiguration;
import com.microsoft.applicationinsights.agent.internal.init.RuntimeConfigurator;
import com.microsoft.applicationinsights.agent.internal.legacyheaders.AiLegacyPropagator;
import com.microsoft.applicationinsights.agent.internal.statsbeat.FeatureStatsbeat;
import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryClient;
Expand All @@ -47,10 +49,34 @@ public class BytecodeUtilImpl implements BytecodeUtilDelegate {

private static final AtomicBoolean alreadyLoggedError = new AtomicBoolean();

public static volatile float samplingPercentage = 100;
// in Azure Functions consumption pool, we don't know at startup whether to enable or not
public static volatile float samplingPercentage = 0;

public static volatile FeatureStatsbeat featureStatsbeat;

public static volatile RuntimeConfigurator runtimeConfigurator;
public static volatile boolean connectionStringConfiguredAtRuntime;

@Override
public void setConnectionString(String connectionString) {
if (!connectionStringConfiguredAtRuntime) {
logger.warn(
"Using com.microsoft.applicationinsights.connectionstring.ConnectionString.configure()"
+ " requires setting the json configuration property"
+ " \"connectionStringConfiguredAtRuntime\" to true");
return;
}
if (TelemetryClient.getActive().getConnectionString() != null) {
logger.warn("Connection string is already set");
return;
}
if (runtimeConfigurator != null) {
RuntimeConfiguration runtimeConfig = runtimeConfigurator.getCurrentConfigCopy();
runtimeConfig.connectionString = connectionString;
runtimeConfigurator.apply(runtimeConfig);
}
}

@Override
public void trackEvent(
@Nullable Date timestamp,
Expand Down Expand Up @@ -80,7 +106,7 @@ public void trackEvent(
telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow());
}
selectivelySetTags(telemetryBuilder, tags);
setConnectionString(telemetryBuilder, connectionString, instrumentationKey);
setConnectionStringOnTelemetry(telemetryBuilder, connectionString, instrumentationKey);

track(telemetryBuilder, tags, true);
}
Expand Down Expand Up @@ -127,7 +153,7 @@ public void trackMetric(
telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow());
}
selectivelySetTags(telemetryBuilder, tags);
setConnectionString(telemetryBuilder, connectionString, instrumentationKey);
setConnectionStringOnTelemetry(telemetryBuilder, connectionString, instrumentationKey);

track(telemetryBuilder, tags, false);
}
Expand Down Expand Up @@ -182,7 +208,7 @@ public void trackDependency(
telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow());
}
selectivelySetTags(telemetryBuilder, tags);
setConnectionString(telemetryBuilder, connectionString, instrumentationKey);
setConnectionStringOnTelemetry(telemetryBuilder, connectionString, instrumentationKey);

track(telemetryBuilder, tags, true);
}
Expand Down Expand Up @@ -223,7 +249,7 @@ public void trackPageView(
telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow());
}
selectivelySetTags(telemetryBuilder, tags);
setConnectionString(telemetryBuilder, connectionString, instrumentationKey);
setConnectionStringOnTelemetry(telemetryBuilder, connectionString, instrumentationKey);

track(telemetryBuilder, tags, true);
}
Expand Down Expand Up @@ -258,7 +284,7 @@ public void trackTrace(
telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow());
}
selectivelySetTags(telemetryBuilder, tags);
setConnectionString(telemetryBuilder, connectionString, instrumentationKey);
setConnectionStringOnTelemetry(telemetryBuilder, connectionString, instrumentationKey);

track(telemetryBuilder, tags, true);
}
Expand Down Expand Up @@ -312,7 +338,7 @@ public void trackRequest(
telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow());
}
selectivelySetTags(telemetryBuilder, tags);
setConnectionString(telemetryBuilder, connectionString, instrumentationKey);
setConnectionStringOnTelemetry(telemetryBuilder, connectionString, instrumentationKey);

track(telemetryBuilder, tags, true);
}
Expand Down Expand Up @@ -352,7 +378,7 @@ public void trackException(
telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow());
}
selectivelySetTags(telemetryBuilder, tags);
setConnectionString(telemetryBuilder, connectionString, instrumentationKey);
setConnectionStringOnTelemetry(telemetryBuilder, connectionString, instrumentationKey);

track(telemetryBuilder, tags, true);
}
Expand Down Expand Up @@ -403,7 +429,7 @@ public void trackAvailability(
telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow());
}
selectivelySetTags(telemetryBuilder, tags);
setConnectionString(telemetryBuilder, connectionString, instrumentationKey);
setConnectionStringOnTelemetry(telemetryBuilder, connectionString, instrumentationKey);

track(telemetryBuilder, tags, false);
}
Expand Down Expand Up @@ -523,7 +549,7 @@ private static void setOperationTagsFromTheCurrentSpan(
}
}

private static void setConnectionString(
private static void setConnectionStringOnTelemetry(
AbstractTelemetryBuilder telemetryBuilder,
@Nullable String connectionString,
@Nullable String instrumentationKey) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.applicationinsights.agent.internal.classicsdk;

import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ASM9;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.RETURN;

import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import javax.annotation.Nullable;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ConnectionStringClassFileTransformer implements ClassFileTransformer {

private static final Logger logger =
LoggerFactory.getLogger(ConnectionStringClassFileTransformer.class);

private static final String BYTECODE_UTIL_INTERNAL_NAME =
"com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil";

private final String unshadedClassName =
UnshadedSdkPackageName.get() + "/connectionstring/ConnectionString";

@Override
@Nullable
public byte[] transform(
@Nullable ClassLoader loader,
@Nullable String className,
@Nullable Class<?> classBeingRedefined,
@Nullable ProtectionDomain protectionDomain,
byte[] classfileBuffer) {

if (!unshadedClassName.equals(className)) {
return null;
}
try {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new ConnectionStringClassVisitor(cw);
ClassReader cr = new ClassReader(classfileBuffer);
cr.accept(cv, 0);
return cw.toByteArray();
} catch (Throwable t) {
logger.error(t.getMessage(), t);
return null;
}
}

private static class ConnectionStringClassVisitor extends ClassVisitor {

private final ClassWriter cw;

private ConnectionStringClassVisitor(ClassWriter cw) {
super(ASM9, cw);
this.cw = cw;
}

@Override
@Nullable
public MethodVisitor visitMethod(
int access,
String name,
String descriptor,
@Nullable String signature,
@Nullable String[] exceptions) {
MethodVisitor mv = cw.visitMethod(access, name, descriptor, signature, exceptions);
if (name.equals("configure") && descriptor.equals("(Ljava/lang/String;)V")) {
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(
INVOKESTATIC,
BYTECODE_UTIL_INTERNAL_NAME,
"setConnectionString",
"(Ljava/lang/String;)V",
false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
return null;
} else {
return mv;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
public class Configuration {

public String connectionString;
// missing connection string will cause the agent to not start up, unless this is set,
// in which case the agent will start, but it won't begin capturing any telemetry until the
// connection string is configured later on
public boolean connectionStringConfiguredAtRuntime =
ConfigurationBuilder.inAzureFunctionsConsumptionWorker();
public Role role = new Role();
public Map<String, String> customDimensions = new HashMap<>();
public Sampling sampling = new Sampling();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ public class RpConfiguration {

public String connectionString;

// intentionally null, so that we can tell if rp is providing or not
public Sampling sampling = new Sampling();

// this is needed in Azure Spring Cloud because it will set the role name to application name
// on behalf of customers by default.
// Note the role doesn't support hot load due to unnecessary currently.
// Note the role doesn't support hot load currently.
public Role role = new Role();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,18 @@
package com.microsoft.applicationinsights.agent.internal.init;

import com.google.auto.service.AutoService;
import com.microsoft.applicationinsights.agent.internal.configuration.ConfigurationBuilder;
import com.microsoft.applicationinsights.agent.internal.httpclient.LazyHttpClient;
import io.opentelemetry.javaagent.extension.AgentListener;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;

@AutoService(AgentListener.class)
public class AfterAgentListener implements AgentListener {

private static volatile AppIdSupplier appIdSupplier;

public static void setAppIdSupplier(AppIdSupplier appIdSupplier) {
AfterAgentListener.appIdSupplier = appIdSupplier;
}

@Override
public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) {
// only safe now to resolve app id because SSL initialization
// triggers loading of java.util.logging (starting with Java 8u231)
// only safe now to make HTTPS calls because Java SSL classes
// trigger loading of java.util.logging (starting with Java 8u231)
// and JBoss/Wildfly need to install their own JUL manager before JUL is initialized.

if (!ConfigurationBuilder.inAzureFunctionsConsumptionWorker()) {
// Delay registering and starting AppId retrieval until the connection string is available
appIdSupplier.updateAppId();
}

LazyHttpClient.safeToInitLatch.countDown();

PerformanceCounterInitializer.initialize(FirstEntryPoint.getConfiguration());
Expand Down
Loading