Skip to content

Commit 87570b4

Browse files
authored
Dead letter logging improvements (#531)
* add serialization for actorrefs * handle timer messages * update jvm version in docker container
1 parent 628a914 commit 87570b4

File tree

9 files changed

+342
-2
lines changed

9 files changed

+342
-2
lines changed

src/main/docker/mad/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
FROM eclipse-temurin:17-jre
15+
FROM eclipse-temurin:21-jre
1616

1717
MAINTAINER arpnetworking
1818

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2015 Groupon.com
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.arpnetworking.configuration.jackson.module.pekko;
17+
18+
import com.arpnetworking.logback.annotations.LogValue;
19+
import com.arpnetworking.steno.LogValueMapFactory;
20+
import com.fasterxml.jackson.core.JsonParser;
21+
import com.fasterxml.jackson.databind.DeserializationContext;
22+
import com.fasterxml.jackson.databind.JsonDeserializer;
23+
import org.apache.pekko.actor.ActorRef;
24+
import org.apache.pekko.actor.ActorSystem;
25+
26+
import java.io.IOException;
27+
28+
/**
29+
* Deserializer for an Pekko ActorRef.
30+
*
31+
* @author Brandon Arp (brandon dot arp at inscopemetrics dot com)
32+
*/
33+
public final class ActorRefDeserializer extends JsonDeserializer<ActorRef> {
34+
/**
35+
* Public constructor.
36+
*
37+
* @param system actor system used to resolve references
38+
*/
39+
public ActorRefDeserializer(final ActorSystem system) {
40+
_system = system;
41+
}
42+
43+
@Override
44+
public ActorRef deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
45+
return _system.provider().resolveActorRef(p.getValueAsString());
46+
}
47+
48+
/**
49+
* Generate a Steno log compatible representation.
50+
*
51+
* @return Steno log compatible representation.
52+
*/
53+
@LogValue
54+
public Object toLogValue() {
55+
return LogValueMapFactory.builder(this)
56+
.put("actorSystem", _system)
57+
.build();
58+
}
59+
60+
@Override
61+
public String toString() {
62+
return toLogValue().toString();
63+
}
64+
65+
private final ActorSystem _system;
66+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2015 Groupon.com
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.arpnetworking.configuration.jackson.module.pekko;
17+
18+
import com.fasterxml.jackson.core.JsonGenerator;
19+
import com.fasterxml.jackson.databind.JsonSerializer;
20+
import com.fasterxml.jackson.databind.SerializerProvider;
21+
import org.apache.pekko.actor.ActorRef;
22+
23+
import java.io.IOException;
24+
25+
/**
26+
* Serializer for an Pekko ActorRef.
27+
*
28+
* @author Ville Koskela (ville dot koskela at inscopemetrics dot com)
29+
*/
30+
public final class ActorRefLoggingSerializer extends JsonSerializer<ActorRef> {
31+
32+
/**
33+
* Public constructor.
34+
*/
35+
public ActorRefLoggingSerializer() { }
36+
37+
@Override
38+
public void serialize(
39+
final ActorRef value,
40+
final JsonGenerator gen,
41+
final SerializerProvider serializers) throws IOException {
42+
gen.writeString(value.toString());
43+
}
44+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2015 Groupon.com
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.arpnetworking.configuration.jackson.module.pekko;
17+
18+
import com.fasterxml.jackson.core.JsonGenerator;
19+
import com.fasterxml.jackson.databind.JsonSerializer;
20+
import com.fasterxml.jackson.databind.SerializerProvider;
21+
import org.apache.pekko.actor.ActorRef;
22+
import org.apache.pekko.serialization.Serialization;
23+
24+
import java.io.IOException;
25+
26+
/**
27+
* Serializer for an Pekko ActorRef.
28+
*
29+
* @author Brandon Arp (brandon dot arp at inscopemetrics dot com)
30+
*/
31+
public final class ActorRefSerializer extends JsonSerializer<ActorRef> {
32+
33+
@Override
34+
public void serialize(
35+
final ActorRef value,
36+
final JsonGenerator gen,
37+
final SerializerProvider serializers) throws IOException {
38+
gen.writeString(Serialization.serializedActorPath(value));
39+
}
40+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2015 Groupon.com
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.arpnetworking.configuration.jackson.module.pekko;
17+
18+
import com.fasterxml.jackson.databind.module.SimpleModule;
19+
import org.apache.pekko.actor.ActorRef;
20+
import org.apache.pekko.actor.TimerSchedulerImpl;
21+
22+
/**
23+
* Jackson module for serializing Pekko objects for use in JSON/Jackson based
24+
* logger serializers(e.g. logback-steno).
25+
*
26+
* @author Ville Koskela (ville dot koskela at inscopemetrics dot com)
27+
*/
28+
public final class PekkoLoggingModule extends SimpleModule {
29+
30+
/**
31+
* Public constructor.
32+
*/
33+
public PekkoLoggingModule() { }
34+
35+
@Override
36+
public void setupModule(final SetupContext context) {
37+
addSerializer(ActorRef.class, new ActorRefLoggingSerializer());
38+
addSerializer(TimerSchedulerImpl.TimerMsg.class, new TimerMessageSerializer());
39+
super.setupModule(context);
40+
}
41+
42+
private static final long serialVersionUID = 6984539942087839964L;
43+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2015 Groupon.com
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.arpnetworking.configuration.jackson.module.pekko;
17+
18+
import com.arpnetworking.logback.annotations.LogValue;
19+
import com.arpnetworking.steno.LogValueMapFactory;
20+
import com.fasterxml.jackson.databind.module.SimpleModule;
21+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
22+
import org.apache.pekko.actor.ActorRef;
23+
import org.apache.pekko.actor.ActorSystem;
24+
25+
import java.io.Serial;
26+
27+
/**
28+
* Jackson module for serializing and deserializing Pekko objects.
29+
*
30+
* @author Brandon Arp (brandon dot arp at inscopemetrics dot com)
31+
*/
32+
public final class PekkoModule extends SimpleModule {
33+
34+
/**
35+
* Public constructor.
36+
*
37+
* @param system the actor system to resolve references
38+
*/
39+
public PekkoModule(final ActorSystem system) {
40+
_system = system;
41+
}
42+
43+
@Override
44+
public void setupModule(final SetupContext context) {
45+
addSerializer(ActorRef.class, new ActorRefSerializer());
46+
addDeserializer(ActorRef.class, new ActorRefDeserializer(_system));
47+
super.setupModule(context);
48+
}
49+
50+
/**
51+
* Generate a Steno log compatible representation.
52+
*
53+
* @return Steno log compatible representation.
54+
*/
55+
@LogValue
56+
public Object toLogValue() {
57+
return LogValueMapFactory.builder(this)
58+
.put("actorSystem", _system)
59+
.build();
60+
}
61+
62+
@Override
63+
public String toString() {
64+
return toLogValue().toString();
65+
}
66+
67+
@SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED")
68+
private final transient ActorSystem _system;
69+
70+
@Serial
71+
private static final long serialVersionUID = 4294591813352245070L;
72+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2025 Brandon Arp
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.arpnetworking.configuration.jackson.module.pekko;
17+
18+
import com.fasterxml.jackson.core.JsonGenerator;
19+
import com.fasterxml.jackson.databind.JsonSerializer;
20+
import com.fasterxml.jackson.databind.SerializerProvider;
21+
import org.apache.pekko.actor.TimerSchedulerImpl;
22+
23+
import java.io.IOException;
24+
25+
/**
26+
* Serializer for a Pekko timer message.
27+
*
28+
* @author Brandon Arp (brandon dot arp at inscopemetrics dot com)
29+
*/
30+
public final class TimerMessageSerializer extends JsonSerializer<TimerSchedulerImpl.TimerMsg> {
31+
@Override
32+
public void serialize(
33+
final TimerSchedulerImpl.TimerMsg timerMsg,
34+
final JsonGenerator jsonGenerator,
35+
final SerializerProvider serializerProvider)
36+
throws IOException {
37+
jsonGenerator.writeStartObject();
38+
jsonGenerator.writeObjectField("type", timerMsg.getClass().getTypeName());
39+
jsonGenerator.writeObjectField("key", timerMsg.key());
40+
jsonGenerator.writeObjectField("generation", timerMsg.generation());
41+
jsonGenerator.writeObjectField("owner", timerMsg.owner());
42+
jsonGenerator.writeEndObject();
43+
}
44+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2019 Dropbox
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
@ParametersAreNonnullByDefault
18+
@ReturnValuesAreNonnullByDefault
19+
package com.arpnetworking.configuration.jackson.module.pekko;
20+
21+
import com.arpnetworking.commons.javax.annotation.ReturnValuesAreNonnullByDefault;
22+
23+
import javax.annotation.ParametersAreNonnullByDefault;

src/main/java/com/arpnetworking/metrics/mad/Main.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717

1818
import ch.qos.logback.classic.LoggerContext;
1919
import com.arpnetworking.commons.builder.Builder;
20+
import com.arpnetworking.commons.jackson.databind.ImmutableObjectMapper;
2021
import com.arpnetworking.commons.jackson.databind.ObjectMapperFactory;
2122
import com.arpnetworking.configuration.jackson.DynamicConfiguration;
2223
import com.arpnetworking.configuration.jackson.HoconFileSource;
2324
import com.arpnetworking.configuration.jackson.JsonNodeFileSource;
2425
import com.arpnetworking.configuration.jackson.JsonNodeSource;
26+
import com.arpnetworking.configuration.jackson.module.pekko.PekkoLoggingModule;
2527
import com.arpnetworking.configuration.triggers.FileTrigger;
2628
import com.arpnetworking.http.Routes;
2729
import com.arpnetworking.http.SupplementalRoutes;
@@ -533,6 +535,12 @@ private static Builder<? extends JsonNodeSource> getFileSourceBuilder(final File
533535
.setFile(configurationFile);
534536
}
535537

538+
private static ObjectMapper createMadObjectMapper() {
539+
final ObjectMapper instance = ObjectMapperFactory.createInstance();
540+
instance.registerModule(new PekkoLoggingModule());
541+
return ImmutableObjectMapper.of(instance);
542+
}
543+
536544
private final AggregatorConfiguration _configuration;
537545

538546
private volatile PipelinesLaunchable _pipelinesLaunchable;
@@ -543,7 +551,7 @@ private static Builder<? extends JsonNodeSource> getFileSourceBuilder(final File
543551

544552
private static final Long INITIAL_DELAY_IN_MILLIS = 0L;
545553
private static final TimeUnit TIME_UNIT = TimeUnit.MILLISECONDS;
546-
private static final ObjectMapper OBJECT_MAPPER = ObjectMapperFactory.getInstance();
554+
private static final ObjectMapper OBJECT_MAPPER = createMadObjectMapper();
547555
private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
548556
private static final Duration SHUTDOWN_TIMEOUT = Duration.create(30, TimeUnit.SECONDS);
549557
private static final Semaphore SHUTDOWN_SEMAPHORE = new Semaphore(0);

0 commit comments

Comments
 (0)