blob: 47c669b2f00e1c48c5bdd60739db8789df863912 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Ericsson
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.tracecompass.incubator.internal.opentracing.core.event;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
import org.eclipse.tracecompass.tmf.core.event.TmfEventField;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* Open Tracing fields. Used as a quick wrapper for Open Tracing log data.
*
* @author Katherine Nadeau
*/
public class OpenTracingField {
private final String fOperationName;
private final ITmfEventField fContent;
private final String fSpanId;
private final Long fStartTime;
private final Long fDuration;
private final @Nullable Map<String, Object> fTags;
private final @Nullable Map<String, Object> fProcessTags;
private String fProcessName;
private static final Gson G_SON = new Gson();
/**
* Get the process id
*
* @param eventString
* the event string
* @return the process id
*/
public static @Nullable String getProcess(String eventString) {
@Nullable
JsonObject root = G_SON.fromJson(eventString, JsonObject.class);
String process = optString(root, IOpenTracingConstants.PROCESS_ID);
return process == null ? "" : process; //$NON-NLS-1$
}
/**
* Parse a JSON string
*
* @param fieldsString
* the string
* @param processField
* the process name and tags
* @return an event field
*/
public static @Nullable OpenTracingField parseJson(String fieldsString, @Nullable String processField) {
@Nullable
JsonObject root = G_SON.fromJson(fieldsString, JsonObject.class);
String name = String.valueOf(optString(root, IOpenTracingConstants.OPERATION_NAME));
if (name == "null") { //$NON-NLS-1$
return null;
}
String traceId = optString(root, IOpenTracingConstants.TRACE_ID);
String spanId = optString(root, IOpenTracingConstants.SPAN_ID);
Integer flags = optInt(root, IOpenTracingConstants.FLAGS);
Long startTime = optLong(root, IOpenTracingConstants.START_TIME);
if (Double.isFinite(startTime)) {
startTime = TmfTimestamp.fromMicros(startTime).toNanos();
}
Long duration = optLong(root, IOpenTracingConstants.DURATION);
if (Double.isFinite(duration)) {
duration = TmfTimestamp.fromMicros(duration).toNanos();
}
Map<@NonNull String, @NonNull Object> fieldsMap = new HashMap<>();
JsonArray refs = optJSONArray(root, IOpenTracingConstants.REFERENCES);
if (refs != null) {
for (int i = 0; i < refs.size(); i++) {
String key = Objects.requireNonNull(refs.get(i).getAsJsonObject().get(IOpenTracingConstants.REFERENCE_TYPE).getAsString());
JsonElement element = Objects.requireNonNull(refs.get(i).getAsJsonObject().get(IOpenTracingConstants.SPAN_ID));
String value = String.valueOf(element.isJsonPrimitive() ? element.getAsJsonPrimitive().getAsString() : element.toString());
fieldsMap.put(IOpenTracingConstants.REFERENCES + '/' + key, value);
}
}
JsonArray tags = optJSONArray(root, IOpenTracingConstants.TAGS);
if (tags != null) {
for (int i = 0; i < tags.size(); i++) {
String key = Objects.requireNonNull(tags.get(i).getAsJsonObject().get(IOpenTracingConstants.KEY).getAsString());
JsonElement element = Objects.requireNonNull(tags.get(i).getAsJsonObject().get(IOpenTracingConstants.VALUE));
String value = String.valueOf(element.isJsonPrimitive() ? element.getAsJsonPrimitive().getAsString() : element.toString());
fieldsMap.put(IOpenTracingConstants.TAGS + '/' + key, value);
}
}
JsonArray logs = optJSONArray(root, IOpenTracingConstants.LOGS);
if (logs != null) {
Map<Long, Map<String, String>> timestampList = new HashMap();
for (int i = 0; i < logs.size(); i++) {
Long timestamp = optLong(logs.get(i).getAsJsonObject(), IOpenTracingConstants.TIMESTAMP);
if (Double.isFinite(timestamp)) {
timestamp = TmfTimestamp.fromMicros(timestamp).toNanos();
}
JsonArray fields = Objects.requireNonNull(logs.get(i).getAsJsonObject().get(IOpenTracingConstants.FIELDS).getAsJsonArray());
Map<String, String> fieldsList = new HashMap();
for (int j = 0; j < fields.size(); j++) {
String key = Objects.requireNonNull(fields.get(j).getAsJsonObject().get(IOpenTracingConstants.KEY).getAsString());
JsonElement element = Objects.requireNonNull(fields.get(j).getAsJsonObject().get(IOpenTracingConstants.VALUE));
String value = String.valueOf(element.isJsonPrimitive() ? element.getAsJsonPrimitive().getAsString() : element.toString());
fieldsList.put(key, value);
}
timestampList.put(timestamp.longValue(), fieldsList);
}
fieldsMap.put(IOpenTracingConstants.LOGS, timestampList);
}
if (traceId == null || spanId == null) {
return null;
}
fieldsMap.put(IOpenTracingConstants.OPERATION_NAME, name);
fieldsMap.put(IOpenTracingConstants.TRACE_ID, traceId);
fieldsMap.put(IOpenTracingConstants.SPAN_ID, spanId);
if (flags != Integer.MIN_VALUE) {
fieldsMap.put(IOpenTracingConstants.FLAGS, flags);
}
fieldsMap.put(IOpenTracingConstants.START_TIME, startTime);
fieldsMap.put(IOpenTracingConstants.DURATION, duration);
String processName = processField == null ? "" : parseProcess(processField, fieldsMap); //$NON-NLS-1$
fieldsMap.put(IOpenTracingConstants.PROCESS_NAME, processName);
return new OpenTracingField(name, fieldsMap, spanId, startTime, duration, processName);
}
/**
* Parse a JSON string of the process and add it in fieldsMap
*
* @param processField
* the string
* @param fieldsMap
* processes list
* @return the process name
*/
public static String parseProcess(String processField, Map<String, Object> fieldsMap) {
@Nullable
JsonObject root = G_SON.fromJson(processField, JsonObject.class);
String name = String.valueOf(optString(root, IOpenTracingConstants.SERVICE_NAME));
if (name == "null") { //$NON-NLS-1$
return ""; //$NON-NLS-1$
}
JsonArray tags = optJSONArray(root, IOpenTracingConstants.TAGS);
if (tags != null) {
for (int i = 0; i < tags.size(); i++) {
String key = Objects.requireNonNull(tags.get(i).getAsJsonObject().get("key").getAsString()); //$NON-NLS-1$
JsonElement element = Objects.requireNonNull(tags.get(i).getAsJsonObject().get("value")); //$NON-NLS-1$
String value = String.valueOf(element.isJsonPrimitive() ? element.getAsJsonPrimitive().getAsString() : element.toString());
fieldsMap.put(IOpenTracingConstants.PROCESS_TAGS + '/' + key, value);
}
}
return name;
}
private static long optLong(JsonObject root, String key) {
JsonElement jsonElement = root.get(key);
return jsonElement != null ? jsonElement.getAsLong() : Long.MIN_VALUE;
}
private static int optInt(JsonObject root, String key) {
JsonElement jsonElement = root.get(key);
return jsonElement != null ? jsonElement.getAsInt() : Integer.MIN_VALUE;
}
private static @Nullable JsonArray optJSONArray(JsonObject root, String key) {
JsonElement jsonElement = root.get(key);
return jsonElement != null ? jsonElement.getAsJsonArray() : null;
}
private static @Nullable String optString(JsonObject root, String key) {
JsonElement jsonElement = root.get(key);
return jsonElement != null ? jsonElement.getAsString() : null;
}
/**
* Constructor
*
* @param name
* operation name
* @param fields
* span fields (arguments)
* @param spanId
* the span id
* @param startTime
* the span start time
* @param duration
* the span duration
* @param processName
* the span process name
*/
private OpenTracingField(String name, Map<String, Object> fields, String spanId, Long startTime, Long duration, String processName) {
fOperationName = name;
ITmfEventField[] array = fields.entrySet().stream()
.map(entry -> new TmfEventField(entry.getKey(), entry.getValue(), null))
.toArray(ITmfEventField[]::new);
fContent = new TmfEventField(ITmfEventField.ROOT_FIELD_ID, fields, array);
fSpanId = spanId;
fStartTime = startTime;
fDuration = duration;
@SuppressWarnings("null")
Map<@NonNull String, @NonNull Object> tags = fields.entrySet().stream()
.filter(entry -> {
return entry.getKey().startsWith(IOpenTracingConstants.TAGS + '/');
})
.collect(Collectors.toMap(entry -> entry.getKey().substring(5), Entry::getValue));
fTags = tags.isEmpty() ? null : tags;
@SuppressWarnings("null")
Map<@NonNull String, @NonNull Object> processTags = fields.entrySet().stream()
.filter(entry -> {
return entry.getKey().startsWith(IOpenTracingConstants.PROCESS_TAGS + '/');
})
.collect(Collectors.toMap(entry -> entry.getKey().substring(12), Entry::getValue));
fProcessTags = processTags.isEmpty() ? null : processTags;
fProcessName = processName;
}
/**
* Get the operation name
*
* @return the operation name
*/
public String getName() {
return fOperationName;
}
/**
* Get the event content
*
* @return the event content
*/
public ITmfEventField getContent() {
return fContent;
}
/**
* Get the span id
*
* @return the span id
*/
public String getSpanId() {
return fSpanId;
}
/**
* Get the span start time
*
* @return the start time
*/
public Long getStartTime() {
return fStartTime;
}
/**
* Get the event duration
*
* @return the duration
*/
public Long getDuration() {
return fDuration;
}
/**
* Get the span tags
*
* @return a map of the tags and their field names
*/
public @Nullable Map<String, Object> getTags() {
return fTags;
}
/**
* Get the span process tags
*
* @return a map of the process tags and their field names
*/
@Nullable
public Map<String, Object> getProcessTags() {
return fProcessTags;
}
/**
* Get the span processName
*
* @return the process name
*/
public String getProcessName() {
return fProcessName;
}
}