Skip to content
Open
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
37 changes: 28 additions & 9 deletions src/main/java/com/datadog/ServerlessCompatAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -16,6 +18,7 @@ enum CloudEnvironment {
AZURE_FUNCTION,
AZURE_SPRING_APP,
GOOGLE_CLOUD_RUN_FUNCTION_1ST_GEN,
GOOGLE_CLOUD_RUN_FUNCTION_2ND_GEN,
UNKNOWN
}

Expand Down Expand Up @@ -50,23 +53,39 @@ public static boolean isLinux() {
}

public static CloudEnvironment getEnvironment() {
Map<String, String> env = System.getenv();
return getEnvironment(System.getenv());
}

static CloudEnvironment getEnvironment(Map<String, String> env) {
List<CloudEnvironment> detected = new ArrayList<>();

if (env.get("FUNCTIONS_EXTENSION_VERSION") != null &&
env.get("FUNCTIONS_WORKER_RUNTIME") != null) {
return CloudEnvironment.AZURE_FUNCTION;
if (env.get("FUNCTIONS_EXTENSION_VERSION") != null
&& env.get("FUNCTIONS_WORKER_RUNTIME") != null) {
detected.add(CloudEnvironment.AZURE_FUNCTION);
Comment on lines 55 to +64
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getEnvironment() behavior changed significantly (multi-detection handling + new Google signature), but there are no unit tests covering these branches. Since the repo already has JUnit tests for ServerlessCompatAgent, consider extracting the detection logic into a package-private helper that accepts an env Map<String,String> so tests can cover each detection path and the "multiple environments" case.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added unit tests in c359922

}

if (env.get("ASCSVCRT_SPRING__APPLICATION__NAME") != null) {
return CloudEnvironment.AZURE_SPRING_APP;
detected.add(CloudEnvironment.AZURE_SPRING_APP);
}
Comment on lines 55 to 69
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions "error when a platform is detected but its name variable is missing", but this change only adds multi-detection handling and a new Google env signature; there’s no new validation/error for a detected platform missing its required name variable. Either implement that validation in getEnvironment()/premain() (with a clear error message) or update the PR description to match the actual behavior.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the PR description


if (env.get("FUNCTION_NAME") != null &&
env.get("GCP_PROJECT") != null) {
return CloudEnvironment.GOOGLE_CLOUD_RUN_FUNCTION_1ST_GEN;
if (env.get("FUNCTION_NAME") != null && env.get("GCP_PROJECT") != null) {
// Set by Google Cloud Functions for older runtimes
detected.add(CloudEnvironment.GOOGLE_CLOUD_RUN_FUNCTION_1ST_GEN);
} else if (env.get("K_SERVICE") != null && env.get("FUNCTION_TARGET") != null) {
// Set by Google Cloud Functions for newer runtimes
detected.add(CloudEnvironment.GOOGLE_CLOUD_RUN_FUNCTION_2ND_GEN);
}

if (detected.isEmpty()) {
return CloudEnvironment.UNKNOWN;
}
if (detected.size() > 1) {
log.error("Multiple cloud environments detected: {}", detected);
Copy link
Copy Markdown

@Lewis-E Lewis-E Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it'd make sense to track gen2/unknown uses of the compat layer, similarly to the telemetry we are thinking about adding for serverless-init? https://datadoghq.atlassian.net/browse/SVLS-8970 (possibility is a separate question)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be interesting if we are able to track that! I can bring it up in the next standup or ask Piyali

return CloudEnvironment.UNKNOWN;
}

return CloudEnvironment.UNKNOWN;
CloudEnvironment environment = detected.get(0);
return environment;
}

public static String getPackageVersion() {
Expand Down
116 changes: 116 additions & 0 deletions src/test/java/com/datadog/ServerlessCompatAgentTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.datadog;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.slf4j.Logger;
import org.slf4j.helpers.NOPLogger;

import static org.junit.jupiter.api.Assertions.*;

class ServerlessCompatAgentTest {

@ParameterizedTest
@CsvSource({
"TRACE, TRACE",
"DEBUG, DEBUG",
"INFO, INFO",
"WARN, WARN",
"ERROR, ERROR",
"CRITICAL, ERROR",
"OFF, null"
})
void testInitLogger(String ddLogLevel, String expectedSlf4jLevel) throws Exception {
Method initLoggerMethod = ServerlessCompatAgent.class.getDeclaredMethod("initLogger", String.class);
initLoggerMethod.setAccessible(true);
Logger logger = (Logger) initLoggerMethod.invoke(null, ddLogLevel);

if ("OFF".equals(ddLogLevel)) {
assertTrue(logger instanceof NOPLogger);
} else {
assertEquals(expectedSlf4jLevel,
System.getProperty("org.slf4j.simpleLogger.defaultLogLevel"));
}
}

@Test
void getEnvironment_returnsUnknownWhenNoVarsSet() {
assertEquals(CloudEnvironment.UNKNOWN,
ServerlessCompatAgent.getEnvironment(new HashMap<>()));
}

@Test
void getEnvironment_detectsAzureFunction() {
Map<String, String> env = new HashMap<>();
env.put("FUNCTIONS_EXTENSION_VERSION", "~4");
env.put("FUNCTIONS_WORKER_RUNTIME", "java");
assertEquals(CloudEnvironment.AZURE_FUNCTION,
ServerlessCompatAgent.getEnvironment(env));
}

@Test
void getEnvironment_requiresBothAzureFunctionVars() {
Map<String, String> env = new HashMap<>();
env.put("FUNCTIONS_EXTENSION_VERSION", "~4");
assertEquals(CloudEnvironment.UNKNOWN,
ServerlessCompatAgent.getEnvironment(env));
}

@Test
void getEnvironment_detectsAzureSpringApp() {
Map<String, String> env = new HashMap<>();
env.put("ASCSVCRT_SPRING__APPLICATION__NAME", "my-app");
assertEquals(CloudEnvironment.AZURE_SPRING_APP,
ServerlessCompatAgent.getEnvironment(env));
}

@Test
void getEnvironment_detectsGcpOlderRuntimes() {
Map<String, String> env = new HashMap<>();
env.put("FUNCTION_NAME", "my-function");
env.put("GCP_PROJECT", "my-project");
assertEquals(CloudEnvironment.GOOGLE_CLOUD_RUN_FUNCTION_1ST_GEN,
ServerlessCompatAgent.getEnvironment(env));
}

@Test
void getEnvironment_requiresBothGcpOlderRuntimesVars() {
Map<String, String> env = new HashMap<>();
env.put("FUNCTION_NAME", "my-function");
assertEquals(CloudEnvironment.UNKNOWN,
ServerlessCompatAgent.getEnvironment(env));
}

@Test
void getEnvironment_detectsGcpNewerRuntimes() {
Map<String, String> env = new HashMap<>();
env.put("K_SERVICE", "my-service");
env.put("FUNCTION_TARGET", "handler");
assertEquals(CloudEnvironment.GOOGLE_CLOUD_RUN_FUNCTION_2ND_GEN,
ServerlessCompatAgent.getEnvironment(env));
}

@Test
void getEnvironment_returnsUnknownWhenMultipleEnvironmentsDetected() {
Map<String, String> env = new HashMap<>();
env.put("FUNCTIONS_EXTENSION_VERSION", "~4");
env.put("FUNCTIONS_WORKER_RUNTIME", "java");
env.put("FUNCTION_NAME", "my-function");
env.put("GCP_PROJECT", "my-project");
assertEquals(CloudEnvironment.UNKNOWN,
ServerlessCompatAgent.getEnvironment(env));
}

@Test
void getEnvironment_bareFunctionNameDoesNotTriggerGcpDetection() {
Map<String, String> env = new HashMap<>();
env.put("FUNCTION_NAME", "my-function");
env.put("FUNCTIONS_EXTENSION_VERSION", "~4");
env.put("FUNCTIONS_WORKER_RUNTIME", "java");
assertEquals(CloudEnvironment.AZURE_FUNCTION,
ServerlessCompatAgent.getEnvironment(env));
}
}
34 changes: 0 additions & 34 deletions src/test/java/test.java

This file was deleted.