org.glowroot.agent.model.DetailMapWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of glowroot-agent-it-harness Show documentation
Show all versions of glowroot-agent-it-harness Show documentation
Glowroot Agent Integration Test Harness
/*
* Copyright 2012-2018 the original author or authors.
*
* 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 org.glowroot.agent.model;
import java.util.List;
import java.util.Map;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.ImmutableList;
import org.glowroot.agent.shaded.org.glowroot.agent.it.harness.shaded.com.google.common.collect.Lists;
import org.glowroot.agent.shaded.org.checkerframework.checker.nullness.qual.Nullable;
import org.glowroot.agent.shaded.org.glowroot.agent.shaded.org.slf4j.Logger;
import org.glowroot.agent.shaded.org.glowroot.agent.shaded.org.slf4j.LoggerFactory;
import org.glowroot.agent.plugin.api.util.Optional;
import org.glowroot.agent.shaded.org.glowroot.wire.api.model.TraceOuterClass.Trace;
public class DetailMapWriter {
private static final Logger logger = LoggerFactory.getLogger(DetailMapWriter.class);
private static final int MESSAGE_CHAR_LIMIT =
Integer.getInteger("glowroot.message.char.limit", 100000);
private DetailMapWriter() {}
public static List toProto(Map detail) {
return mapToProto(detail);
}
private static Trace.DetailEntry createDetailEntry(String name, @Nullable Object value) {
if (value instanceof Map) {
return Trace.DetailEntry.newBuilder()
.setName(name)
.addAllChildEntry(mapToProto((Map, ?>) value))
.build();
} else if (value instanceof List) {
return Trace.DetailEntry.newBuilder()
.setName(name)
.addAllValue(listToProto((List>) value))
.build();
} else {
return Trace.DetailEntry.newBuilder()
.setName(name)
.addAllValue(singleObjectToProto(value))
.build();
}
}
private static List mapToProto(Map, ?> map) {
List entries = Lists.newArrayListWithCapacity(map.size());
for (Map.Entry, ?> entry : map.entrySet()) {
Object key = entry.getKey();
if (key == null) {
// skip invalid data
logger.warn("detail map has null key");
continue;
}
String name;
if (key instanceof String) {
name = (String) key;
} else {
name = convertToStringAndTruncate(key);
}
entries.add(createDetailEntry(name, entry.getValue()));
}
return entries;
}
private static List listToProto(List> list) {
List detailValues = Lists.newArrayListWithCapacity(list.size());
for (Object item : (List>) list) {
Trace.DetailValue detailValue = createValue(item);
if (detailValue != null) {
detailValues.add(detailValue);
}
}
return detailValues;
}
private static List singleObjectToProto(@Nullable Object value) {
Trace.DetailValue detailValue = createValue(value);
if (detailValue == null) {
return ImmutableList.of();
} else {
return ImmutableList.of(detailValue);
}
}
private static Trace. /*@Nullable*/ DetailValue createValue(
@Nullable Object possiblyOptionalValue) {
Object value = stripOptional(possiblyOptionalValue);
if (value == null) {
// add nothing (as a corollary, this will strip null/Optional.absent() items from lists)
return null;
} else if (value instanceof String) {
return Trace.DetailValue.newBuilder().setString((String) value).build();
} else if (value instanceof Boolean) {
return Trace.DetailValue.newBuilder().setBoolean((Boolean) value).build();
} else if (value instanceof Long) {
return Trace.DetailValue.newBuilder().setLong((Long) value).build();
} else if (value instanceof Integer) {
return Trace.DetailValue.newBuilder().setLong((Integer) value).build();
} else if (value instanceof Number) {
return Trace.DetailValue.newBuilder().setDouble(((Number) value).doubleValue()).build();
} else {
logger.warn("detail map has unexpected value type: {}", value.getClass().getName());
return Trace.DetailValue.newBuilder().setString(convertToStringAndTruncate(value))
.build();
}
}
private static @Nullable Object stripOptional(@Nullable Object value) {
if (value == null) {
return null;
}
if (value instanceof Optional) {
Optional> val = (Optional>) value;
return val.orNull();
}
return value;
}
// unexpected keys and values are not truncated in org.glowroot.agent.plugin.api.MessageImpl, so
// need to be truncated here after converting them to strings
private static String convertToStringAndTruncate(Object obj) {
String str = obj.toString();
if (str == null) {
return "";
}
return truncate(str);
}
private static String truncate(String s) {
if (s.length() <= MESSAGE_CHAR_LIMIT) {
return s;
} else {
return s.substring(0, MESSAGE_CHAR_LIMIT) + " [truncated to " + MESSAGE_CHAR_LIMIT
+ " characters]";
}
}
}