Skip to content

Commit 9df64af

Browse files
author
Paul Schellenberg
committed
Allow for STDOUT overrides when using an AgentBasedEnvironment
1 parent 472805d commit 9df64af

File tree

3 files changed

+120
-17
lines changed

3 files changed

+120
-17
lines changed

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ With Docker images, using the `awslogs` log driver will send your container logs
3838
## ECS and Fargate
3939

4040
With ECS and Fargate, you can use the `awslogs` log driver to have your logs sent to CloudWatch Logs on your behalf. After configuring your task to use the `awslogs` log driver, you may write your EMF logs to STDOUT and they will be processed.
41+
To write your EMF logs to STDOUT, set the environment variable `WRITE_TO_STDOUT=true`
4142

4243
[ECS documentation on `awslogs` log driver](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html)
4344

src/main/java/software/amazon/cloudwatchlogs/emf/environment/AgentBasedEnvironment.java

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,26 @@
2020
import lombok.extern.slf4j.Slf4j;
2121
import software.amazon.cloudwatchlogs.emf.Constants;
2222
import software.amazon.cloudwatchlogs.emf.config.Configuration;
23+
import software.amazon.cloudwatchlogs.emf.config.SystemWrapper;
2324
import software.amazon.cloudwatchlogs.emf.sinks.AgentSink;
25+
import software.amazon.cloudwatchlogs.emf.sinks.ConsoleSink;
2426
import software.amazon.cloudwatchlogs.emf.sinks.Endpoint;
2527
import software.amazon.cloudwatchlogs.emf.sinks.ISink;
2628
import software.amazon.cloudwatchlogs.emf.sinks.SocketClientFactory;
2729
import software.amazon.cloudwatchlogs.emf.sinks.retry.FibonacciRetryStrategy;
2830

2931
@Slf4j
3032
public abstract class AgentBasedEnvironment implements Environment {
33+
private static final String WRITE_TO_STDOUT = "WRITE_TO_STDOUT";
34+
private final boolean shouldWriteToStdout;
3135
private final Configuration config;
3236
private ISink sink;
3337

3438
protected AgentBasedEnvironment(Configuration config) {
3539
this.config = config;
40+
shouldWriteToStdout = Optional.ofNullable(SystemWrapper.getenv(WRITE_TO_STDOUT))
41+
.map(Boolean::parseBoolean)
42+
.orElse(false);
3643
}
3744

3845
@Override
@@ -67,27 +74,31 @@ public String getLogStreamName() {
6774
@Override
6875
public ISink getSink() {
6976
if (sink == null) {
70-
Endpoint endpoint;
71-
if (config.getAgentEndpoint().isPresent()) {
72-
endpoint = Endpoint.fromURL(config.getAgentEndpoint().get());
77+
if (shouldWriteToStdout) {
78+
sink = new ConsoleSink();
7379
} else {
74-
log.info(
80+
Endpoint endpoint;
81+
if (config.getAgentEndpoint().isPresent()) {
82+
endpoint = Endpoint.fromURL(config.getAgentEndpoint().get());
83+
} else {
84+
log.info(
7585
"Endpoint is not defined. Using default: {}",
7686
Endpoint.DEFAULT_TCP_ENDPOINT);
77-
endpoint = Endpoint.DEFAULT_TCP_ENDPOINT;
78-
}
79-
sink =
87+
endpoint = Endpoint.DEFAULT_TCP_ENDPOINT;
88+
}
89+
sink =
8090
new AgentSink(
81-
getLogGroupName(),
82-
getLogStreamName(),
83-
endpoint,
84-
new SocketClientFactory(),
85-
config.getAsyncBufferSize(),
86-
() ->
87-
new FibonacciRetryStrategy(
88-
Constants.MIN_BACKOFF_MILLIS,
89-
Constants.MAX_BACKOFF_MILLIS,
90-
Constants.MAX_BACKOFF_JITTER));
91+
getLogGroupName(),
92+
getLogStreamName(),
93+
endpoint,
94+
new SocketClientFactory(),
95+
config.getAsyncBufferSize(),
96+
() ->
97+
new FibonacciRetryStrategy(
98+
Constants.MIN_BACKOFF_MILLIS,
99+
Constants.MAX_BACKOFF_MILLIS,
100+
Constants.MAX_BACKOFF_JITTER));
101+
}
91102
}
92103
return sink;
93104
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package software.amazon.cloudwatchlogs.emf.environment;
2+
3+
import org.junit.Before;
4+
import org.junit.Test;
5+
import org.junit.runner.RunWith;
6+
import org.powermock.api.mockito.PowerMockito;
7+
import org.powermock.core.classloader.annotations.PrepareForTest;
8+
import org.powermock.modules.junit4.PowerMockRunner;
9+
import software.amazon.cloudwatchlogs.emf.config.Configuration;
10+
import software.amazon.cloudwatchlogs.emf.config.SystemWrapper;
11+
import software.amazon.cloudwatchlogs.emf.model.MetricsContext;
12+
import software.amazon.cloudwatchlogs.emf.sinks.AgentSink;
13+
import software.amazon.cloudwatchlogs.emf.sinks.ConsoleSink;
14+
import software.amazon.cloudwatchlogs.emf.sinks.Endpoint;
15+
import software.amazon.cloudwatchlogs.emf.sinks.ISink;
16+
17+
import static org.junit.Assert.assertEquals;
18+
import static org.powermock.api.mockito.PowerMockito.mock;
19+
20+
@RunWith(PowerMockRunner.class)
21+
@PrepareForTest( {SystemWrapper.class, AgentBasedEnvironment.class} )
22+
public class AgentBasedEnvironmentTest {
23+
public static class AgentBasedEnvironmentTestImplementation extends AgentBasedEnvironment {
24+
protected AgentBasedEnvironmentTestImplementation(Configuration config) { super(config); }
25+
@Override
26+
public boolean probe() { return false; }
27+
@Override
28+
public String getType() { return null; }
29+
@Override
30+
public void configureContext(MetricsContext context) { }
31+
}
32+
33+
private Configuration configuration;
34+
35+
@Before
36+
public void setup() {
37+
this.configuration = new Configuration();
38+
}
39+
40+
@Test
41+
public void testGetSinkWithDefaultEndpoint() throws Exception {
42+
AgentSink mockedSink = mock(AgentSink.class);
43+
PowerMockito.whenNew(AgentSink.class).withAnyArguments().then(invocation -> {
44+
Endpoint endpoint = invocation.getArgument(2);
45+
assertEquals(Endpoint.DEFAULT_TCP_ENDPOINT, endpoint);
46+
return mockedSink;
47+
});
48+
49+
AgentBasedEnvironment env = new AgentBasedEnvironmentTestImplementation(configuration);
50+
ISink sink = env.getSink();
51+
52+
assertEquals(mockedSink, sink);
53+
}
54+
55+
@Test
56+
public void testGetSinkWithConfiguredEndpoint() throws Exception {
57+
String endpointUrl = "http://configured-endpoint:1234";
58+
configuration.setAgentEndpoint(endpointUrl);
59+
AgentSink mockedSink = mock(AgentSink.class);
60+
PowerMockito.whenNew(AgentSink.class).withAnyArguments().then(invocation -> {
61+
Endpoint endpoint = invocation.getArgument(2);
62+
assertEquals(Endpoint.fromURL(endpointUrl), endpoint);
63+
return mockedSink;
64+
});
65+
66+
AgentBasedEnvironment env = new AgentBasedEnvironmentTestImplementation(configuration);
67+
ISink sink = env.getSink();
68+
69+
assertEquals(mockedSink, sink);
70+
}
71+
72+
@Test
73+
public void testGetSinkOverrideToStdOut() {
74+
PowerMockito.mockStatic(SystemWrapper.class);
75+
PowerMockito.when(SystemWrapper.getenv("WRITE_TO_STDOUT")).thenReturn("true");
76+
77+
AgentBasedEnvironment env = new AgentBasedEnvironmentTestImplementation(configuration);
78+
ISink sink = env.getSink();
79+
80+
assertEquals(ConsoleSink.class, sink.getClass());
81+
}
82+
83+
@Test
84+
public void testGetSinkOverrideToStdOutFailFastOnImproperOverride() throws Exception {
85+
PowerMockito.mockStatic(SystemWrapper.class);
86+
// Will only override if this env is explicitly "true"
87+
PowerMockito.when(SystemWrapper.getenv("WRITE_TO_STDOUT")).thenReturn("notABool");
88+
89+
testGetSinkWithDefaultEndpoint();
90+
}
91+
}

0 commit comments

Comments
 (0)