From: Alexandre Montplaisir Date: Fri, 12 Feb 2016 20:28:07 +0000 (-0500) Subject: Pass the Java app context information using two separate arrays X-Git-Tag: v2.8.0-rc1~34 X-Git-Url: http://git.liburcu.org/?p=lttng-ust.git;a=commitdiff_plain;h=b1ca4c5fae8a541330c940c45dd5f3bd93dbf46a Pass the Java app context information using two separate arrays Instead of using one array with length limits for strings, we can pass two separate arrays: the first will continue to contain fixed- size entries, but instead of 256 bytes for strings, we will use 4-byte offsets to a second array, which will contain only those variable-length strings. The advantage is that we pass less bytes overall, and we don't limit the context names or values to 256 bytes anymore. Signed-off-by: Alexandre Montplaisir Signed-off-by: Mathieu Desnoyers --- diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java index be613043..878f44ef 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoSerializer.java @@ -17,6 +17,8 @@ package org.lttng.ust.agent.context; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -30,18 +32,34 @@ import org.lttng.ust.agent.utils.LttngUstAgentLogger; * This class is used to serialize the list of "context info" objects to pass * through JNI. * - * The protocol expects a single byte array parameter. This byte array consists - * of a series of fixed-size entries, where each entry contains the following - * elements (with their size in bytes in parenthesis): + * The protocol expects two byte array parameters, which are contained here in + * the {@link SerializedContexts} inner class. + * + * The first byte array is called the "entries array", and contains fixed-size + * entries, one per context element. + * + * The second one is the "strings array", it is of variable length and used to + * hold the variable-length strings. Each one of these strings is formatted as a + * UTF-8 C-string, meaning in will end with a "\0" byte to indicate its end. + * Entries in the first array may refer to offsets in the second array to point + * to relevant strings. + * + * The fixed-size entries in the entries array contain the following elements + * (size in bytes in parentheses): * *
    - *
  • The full context name, like "$app.myprovider:mycontext" (256)
  • + *
  • The offset in the strings array pointing to the full context name, like + * "$app.myprovider:mycontext" (4)
  • *
  • The context value type (1)
  • - *
  • The context value itself(256)
  • + *
  • The context value itself (8)
  • *
* - * So the total size of each entry is 513 bytes. All unused bytes will be - * zero'ed. + * The context value type will indicate how many bytes are used for the value. + * If the it is of String type, then we use 4 bytes to represent the offset in + * the strings array. + * + * So the total size of each entry is 13 bytes. All unused bytes (for context + * values shorter than 8 bytes for example) will be zero'ed. * * @author Alexandre Montplaisir */ @@ -69,12 +87,48 @@ public class ContextInfoSerializer { } } + /** + * Class used to wrap the two byte arrays returned by + * {@link #queryAndSerializeRequestedContexts}. + */ + public static class SerializedContexts { + + private final byte[] contextEntries; + private final byte[] contextStrings; + + /** + * Constructor + * + * @param entries + * Arrays for the fixed-size context entries. + * @param strings + * Arrays for variable-length strings + */ + public SerializedContexts(byte[] entries, byte[] strings) { + contextEntries = entries; + contextStrings = strings; + } + + /** + * @return The entries array + */ + public byte[] getEntriesArray() { + return contextEntries; + } + + /** + * @return The strings array + */ + public byte[] getStringsArray() { + return contextStrings; + } + } + private static final String UST_APP_CTX_PREFIX = "$app."; - private static final int ELEMENT_LENGTH = 256; - private static final int ENTRY_LENGTH = 513; + private static final int ENTRY_LENGTH = 13; private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder(); private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); - private static final byte[] EMPTY_ARRAY = new byte[0]; + private static final SerializedContexts EMPTY_CONTEXTS = new SerializedContexts(new byte[0], new byte[0]); /** * From the list of requested contexts in the tracing session, look them up @@ -88,16 +142,10 @@ public class ContextInfoSerializer { * @return The byte array representing the intersection of the requested and * available contexts. */ - public static byte[] queryAndSerializeRequestedContexts(Collection>> enabledContexts) { + public static SerializedContexts queryAndSerializeRequestedContexts(Collection>> enabledContexts) { if (enabledContexts.isEmpty()) { /* Early return if there is no requested context information */ - return EMPTY_ARRAY; - } - - /* Compute the total number of contexts (flatten the map) */ - int totalArraySize = 0; - for (Map.Entry> contexts : enabledContexts) { - totalArraySize += contexts.getValue().size() * ENTRY_LENGTH; + return EMPTY_CONTEXTS; } ContextInfoManager contextManager; @@ -108,110 +156,140 @@ public class ContextInfoSerializer { * The JNI library is not available, do not send any context * information. No retriever could have been defined anyways. */ - return EMPTY_ARRAY; + return EMPTY_CONTEXTS; } - ByteBuffer buffer = ByteBuffer.allocate(totalArraySize); - buffer.order(NATIVE_ORDER); - buffer.clear(); - - for (Map.Entry> entry : enabledContexts) { - String requestedRetrieverName = entry.getKey(); - Map requestedContexts = entry.getValue(); - - IContextInfoRetriever retriever = contextManager.getContextInfoRetriever(requestedRetrieverName); - - for (String requestedContext : requestedContexts.keySet()) { - Object contextInfo; - if (retriever == null) { - contextInfo = null; - } else { - contextInfo = retriever.retrieveContextInfo(requestedContext); - /* - * 'contextInfo' can still be null here, which would - * indicate the retriever does not supply this context. We - * will still write this information so that the tracer can - * know about it. - */ - } + /* Compute the total number of contexts (flatten the map) */ + int totalArraySize = 0; + for (Map.Entry> contexts : enabledContexts) { + totalArraySize += contexts.getValue().size() * ENTRY_LENGTH; + } + + /* Prepare the ByteBuffer that will generate the "entries" array */ + ByteBuffer entriesBuffer = ByteBuffer.allocate(totalArraySize); + entriesBuffer.order(NATIVE_ORDER); + entriesBuffer.clear(); + + /* Prepare the streams that will generate the "strings" array */ + ByteArrayOutputStream stringsBaos = new ByteArrayOutputStream(); + DataOutputStream stringsDos = new DataOutputStream(stringsBaos); + + try { + for (Map.Entry> entry : enabledContexts) { + String requestedRetrieverName = entry.getKey(); + Map requestedContexts = entry.getValue(); + + IContextInfoRetriever retriever = contextManager.getContextInfoRetriever(requestedRetrieverName); + + for (String requestedContext : requestedContexts.keySet()) { + Object contextInfo; + if (retriever == null) { + contextInfo = null; + } else { + contextInfo = retriever.retrieveContextInfo(requestedContext); + /* + * 'contextInfo' can still be null here, which would + * indicate the retriever does not supply this context. + * We will still write this information so that the + * tracer can know about it. + */ + } - /* Serialize the result to the buffer */ - // FIXME Eventually pass the retriever name only once? - String fullContextName = (UST_APP_CTX_PREFIX + requestedRetrieverName + ':' + requestedContext); - byte[] strArray = fullContextName.getBytes(UTF8_CHARSET); - int remainingBytes = ELEMENT_LENGTH - strArray.length; - // FIXME Handle case where name is too long... - buffer.put(strArray); - buffer.position(buffer.position() + remainingBytes); + /* Serialize the result to the buffers */ + // FIXME Eventually pass the retriever name only once? + String fullContextName = (UST_APP_CTX_PREFIX + requestedRetrieverName + ':' + requestedContext); + byte[] strArray = fullContextName.getBytes(UTF8_CHARSET); - LttngUstAgentLogger.log(ContextInfoSerializer.class, - "ContextInfoSerializer: Context to be sent through JNI: " + fullContextName + '=' + - (contextInfo == null ? "null" : contextInfo.toString())); + entriesBuffer.putInt(stringsDos.size()); + stringsDos.write(strArray); + stringsDos.writeChar('\0'); - serializeContextInfo(buffer, contextInfo); + LttngUstAgentLogger.log(ContextInfoSerializer.class, + "ContextInfoSerializer: Context to be sent through JNI: " + fullContextName + '=' + + (contextInfo == null ? "null" : contextInfo.toString())); + + serializeContextInfo(entriesBuffer, stringsDos, contextInfo); + } } + + stringsDos.flush(); + stringsBaos.flush(); + + } catch (IOException e) { + /* + * Should not happen because we are wrapping a + * ByteArrayOutputStream, which writes to memory + */ + e.printStackTrace(); } - return buffer.array(); + + byte[] entriesArray = entriesBuffer.array(); + byte[] stringsArray = stringsBaos.toByteArray(); + return new SerializedContexts(entriesArray, stringsArray); } - private static void serializeContextInfo(ByteBuffer buffer, Object contextInfo) { + private static final int CONTEXT_VALUE_LENGTH = 8; + + private static void serializeContextInfo(ByteBuffer entriesBuffer, DataOutputStream stringsDos, Object contextInfo) throws IOException { int remainingBytes; if (contextInfo == null) { - buffer.put(DataType.NULL.getValue()); - remainingBytes = ELEMENT_LENGTH; + entriesBuffer.put(DataType.NULL.getValue()); + remainingBytes = CONTEXT_VALUE_LENGTH; } else if (contextInfo instanceof Integer) { - buffer.put(DataType.INTEGER.getValue()); - buffer.putInt(((Integer) contextInfo).intValue()); - remainingBytes = ELEMENT_LENGTH - 4; + entriesBuffer.put(DataType.INTEGER.getValue()); + entriesBuffer.putInt(((Integer) contextInfo).intValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 4; } else if (contextInfo instanceof Long) { - buffer.put(DataType.LONG.getValue()); - buffer.putLong(((Long) contextInfo).longValue()); - remainingBytes = ELEMENT_LENGTH - 8; + entriesBuffer.put(DataType.LONG.getValue()); + entriesBuffer.putLong(((Long) contextInfo).longValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 8; } else if (contextInfo instanceof Double) { - buffer.put(DataType.DOUBLE.getValue()); - buffer.putDouble(((Double) contextInfo).doubleValue()); - remainingBytes = ELEMENT_LENGTH - 8; + entriesBuffer.put(DataType.DOUBLE.getValue()); + entriesBuffer.putDouble(((Double) contextInfo).doubleValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 8; } else if (contextInfo instanceof Float) { - buffer.put(DataType.FLOAT.getValue()); - buffer.putFloat(((Float) contextInfo).floatValue()); - remainingBytes = ELEMENT_LENGTH - 4; + entriesBuffer.put(DataType.FLOAT.getValue()); + entriesBuffer.putFloat(((Float) contextInfo).floatValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 4; } else if (contextInfo instanceof Byte) { - buffer.put(DataType.BYTE.getValue()); - buffer.put(((Byte) contextInfo).byteValue()); - remainingBytes = ELEMENT_LENGTH - 1; + entriesBuffer.put(DataType.BYTE.getValue()); + entriesBuffer.put(((Byte) contextInfo).byteValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 1; } else if (contextInfo instanceof Short) { - buffer.put(DataType.SHORT.getValue()); - buffer.putShort(((Short) contextInfo).shortValue()); - remainingBytes = ELEMENT_LENGTH - 2; + entriesBuffer.put(DataType.SHORT.getValue()); + entriesBuffer.putShort(((Short) contextInfo).shortValue()); + remainingBytes = CONTEXT_VALUE_LENGTH - 2; } else if (contextInfo instanceof Boolean) { - buffer.put(DataType.BOOLEAN.getValue()); + entriesBuffer.put(DataType.BOOLEAN.getValue()); boolean b = ((Boolean) contextInfo).booleanValue(); /* Converted to one byte, write 1 for true, 0 for false */ - buffer.put((byte) (b ? 1 : 0)); - remainingBytes = ELEMENT_LENGTH - 1; + entriesBuffer.put((byte) (b ? 1 : 0)); + remainingBytes = CONTEXT_VALUE_LENGTH - 1; } else { - /* We'll write the object as a string. Also includes the case of Character. */ + /* Also includes the case of Character. */ + /* + * We'll write the object as a string, into the strings array. We + * will write the corresponding offset to the entries array. + */ String str = contextInfo.toString(); byte[] strArray = str.getBytes(UTF8_CHARSET); - buffer.put(DataType.STRING.getValue()); - if (strArray.length >= ELEMENT_LENGTH) { - /* Trim the string to the max allowed length */ - buffer.put(strArray, 0, ELEMENT_LENGTH); - remainingBytes = 0; - } else { - buffer.put(strArray); - remainingBytes = ELEMENT_LENGTH - strArray.length; - } + entriesBuffer.put(DataType.STRING.getValue()); + + entriesBuffer.putInt(stringsDos.size()); + stringsDos.write(strArray); + stringsDos.writeChar('\0'); + + remainingBytes = CONTEXT_VALUE_LENGTH - 4; } - buffer.position(buffer.position() + remainingBytes); + entriesBuffer.position(entriesBuffer.position() + remainingBytes); } } diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java index b1f0d019..e4d399f7 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngJulApi.java @@ -41,5 +41,6 @@ final class LttngJulApi { long millis, int log_level, int thread_id, - byte[] contextInformation); + byte[] contextEntries, + byte[] contextStrings); } diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java index 535a2a3f..00c5c48c 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-jul/org/lttng/ust/agent/jul/LttngLogHandler.java @@ -123,7 +123,7 @@ public class LttngLogHandler extends Handler implements ILttngHandler { /* Retrieve all the requested context information we can find */ Collection>> enabledContexts = agent.getEnabledAppContexts(); - byte[] contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts); + ContextInfoSerializer.SerializedContexts contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts); eventCount.incrementAndGet(); @@ -139,7 +139,8 @@ public class LttngLogHandler extends Handler implements ILttngHandler { record.getMillis(), record.getLevel().intValue(), record.getThreadID(), - contextInfo); + contextInfo.getEntriesArray(), + contextInfo.getStringsArray()); } } diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java index 61a04187..035864c2 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLog4jApi.java @@ -45,5 +45,6 @@ final class LttngLog4jApi { long timestamp, int loglevel, String thread_name, - byte[] contextInformation); + byte[] contextEntries, + byte[] contextStrings); } diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java index 5c6df4df..92b76de2 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-log4j/org/lttng/ust/agent/log4j/LttngLogAppender.java @@ -122,7 +122,7 @@ public class LttngLogAppender extends AppenderSkeleton implements ILttngHandler /* Retrieve all the requested context information we can find */ Collection>> enabledContexts = agent.getEnabledAppContexts(); - byte[] contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts); + ContextInfoSerializer.SerializedContexts contextInfo = ContextInfoSerializer.queryAndSerializeRequestedContexts(enabledContexts); eventCount.incrementAndGet(); @@ -135,7 +135,8 @@ public class LttngLogAppender extends AppenderSkeleton implements ILttngHandler event.getTimeStamp(), event.getLevel().toInt(), event.getThreadName(), - contextInfo); + contextInfo.getEntriesArray(), + contextInfo.getStringsArray()); } } diff --git a/liblttng-ust-java-agent/jni/common/lttng_ust_context.c b/liblttng-ust-java-agent/jni/common/lttng_ust_context.c index 8cc4087f..f412cc18 100644 --- a/liblttng-ust-java-agent/jni/common/lttng_ust_context.c +++ b/liblttng-ust-java-agent/jni/common/lttng_ust_context.c @@ -28,10 +28,6 @@ #include "helper.h" #include "lttng_ust_context.h" -#define LTTNG_UST_JNI_CONTEXT_NAME_LEN 256 -/* TODO: the value should be variable length. */ -#define LTTNG_UST_JNI_VALUE_LEN 256 - enum lttng_ust_jni_type { JNI_TYPE_NULL = 0, JNI_TYPE_INTEGER = 1, @@ -44,8 +40,8 @@ enum lttng_ust_jni_type { JNI_TYPE_STRING = 8, }; -struct lttng_ust_jni_ctx { - char context_name[LTTNG_UST_JNI_CONTEXT_NAME_LEN]; +struct lttng_ust_jni_ctx_entry { + int32_t context_name_offset; char type; /* enum lttng_ust_jni_type */ union { int32_t _integer; @@ -55,33 +51,47 @@ struct lttng_ust_jni_ctx { signed char _byte; int16_t _short; signed char _boolean; - char _string[LTTNG_UST_JNI_VALUE_LEN]; + int32_t _string_offset; } value; } __attribute__((packed)); /* TLS passing context info from JNI to callbacks. */ __thread struct lttng_ust_jni_tls lttng_ust_context_info_tls; -static struct lttng_ust_jni_ctx *lookup_ctx_by_name(const char *ctx_name) +static const char *get_ctx_string_at_offset(int32_t offset) +{ + signed char *ctx_strings_array = lttng_ust_context_info_tls.ctx_strings; + + if (offset < 0 || offset >= lttng_ust_context_info_tls.ctx_strings_len) { + return NULL; + } + return (const char *) (ctx_strings_array + offset); +} + +static struct lttng_ust_jni_ctx_entry *lookup_ctx_by_name(const char *ctx_name) { - struct lttng_ust_jni_ctx *ctx_array = lttng_ust_context_info_tls.ctx; - int i, len = lttng_ust_context_info_tls.len / sizeof(struct lttng_ust_jni_ctx); + struct lttng_ust_jni_ctx_entry *ctx_entries_array = lttng_ust_context_info_tls.ctx_entries; + int i, len = lttng_ust_context_info_tls.ctx_entries_len / sizeof(struct lttng_ust_jni_ctx_entry); for (i = 0; i < len; i++) { - if (strcmp(ctx_array[i].context_name, ctx_name) == 0) - return &ctx_array[i]; + int32_t offset = ctx_entries_array[i].context_name_offset; + const char *string = get_ctx_string_at_offset(offset); + + if (string && strcmp(string, ctx_name) == 0) { + return &ctx_entries_array[i]; + } } return NULL; - } static size_t get_size_cb(struct lttng_ctx_field *field, size_t offset) { - struct lttng_ust_jni_ctx *jctx; + struct lttng_ust_jni_ctx_entry *jctx; size_t size = 0; const char *ctx_name = field->event_field.name; enum lttng_ust_jni_type jni_type; + size += lib_ring_buffer_align(offset, lttng_alignof(char)); size += sizeof(char); /* tag */ jctx = lookup_ctx_by_name(ctx_name); @@ -119,8 +129,16 @@ static size_t get_size_cb(struct lttng_ctx_field *field, size_t offset) size += sizeof(char); /* variant */ break; case JNI_TYPE_STRING: - size += strlen(jctx->value._string) + 1; + { + /* The value is an offset, the string is in the "strings" array */ + int32_t string_offset = jctx->value._string_offset; + const char *string = get_ctx_string_at_offset(string_offset); + + if (string) { + size += strlen(string) + 1; + } break; + } default: abort(); } @@ -132,7 +150,7 @@ static void record_cb(struct lttng_ctx_field *field, struct lttng_ust_lib_ring_buffer_ctx *ctx, struct lttng_channel *chan) { - struct lttng_ust_jni_ctx *jctx; + struct lttng_ust_jni_ctx_entry *jctx; const char *ctx_name = field->event_field.name; enum lttng_ust_jni_type jni_type; char sel_char; @@ -229,12 +247,19 @@ static void record_cb(struct lttng_ctx_field *field, } case JNI_TYPE_STRING: { - const char *str = jctx->value._string; - - sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING; + int32_t offset = jctx->value._string_offset; + const char *str = get_ctx_string_at_offset(offset); + + if (str) { + sel_char = LTTNG_UST_DYNAMIC_TYPE_STRING; + } else { + sel_char = LTTNG_UST_DYNAMIC_TYPE_NONE; + } lib_ring_buffer_align_ctx(ctx, lttng_alignof(char)); chan->ops->event_write(ctx, &sel_char, sizeof(sel_char)); - chan->ops->event_write(ctx, str, strlen(str) + 1); + if (str) { + chan->ops->event_write(ctx, str, strlen(str) + 1); + } break; } default: @@ -245,7 +270,7 @@ static void record_cb(struct lttng_ctx_field *field, static void get_value_cb(struct lttng_ctx_field *field, struct lttng_ctx_value *value) { - struct lttng_ust_jni_ctx *jctx; + struct lttng_ust_jni_ctx_entry *jctx; const char *ctx_name = field->event_field.name; enum lttng_ust_jni_type jni_type; @@ -289,9 +314,18 @@ static void get_value_cb(struct lttng_ctx_field *field, value->u.s64 = (int64_t) jctx->value._boolean; break; case JNI_TYPE_STRING: - value->sel = LTTNG_UST_DYNAMIC_TYPE_STRING; - value->u.str = jctx->value._string; + { + int32_t offset = jctx->value._string_offset; + const char *str = get_ctx_string_at_offset(offset); + + if (str) { + value->sel = LTTNG_UST_DYNAMIC_TYPE_STRING; + value->u.str = str; + } else { + value->sel = LTTNG_UST_DYNAMIC_TYPE_NONE; + } break; + } default: abort(); } diff --git a/liblttng-ust-java-agent/jni/common/lttng_ust_context.h b/liblttng-ust-java-agent/jni/common/lttng_ust_context.h index 2bdef3ae..415f7de2 100644 --- a/liblttng-ust-java-agent/jni/common/lttng_ust_context.h +++ b/liblttng-ust-java-agent/jni/common/lttng_ust_context.h @@ -19,11 +19,13 @@ #ifndef LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_ #define LIBLTTNG_UST_JAVA_AGENT_JNI_COMMON_LTTNG_UST_CONTEXT_H_ -struct lttng_ust_jni_ctx; +struct lttng_ust_jni_ctx_entry; struct lttng_ust_jni_tls { - struct lttng_ust_jni_ctx *ctx; - int32_t len; + struct lttng_ust_jni_ctx_entry *ctx_entries; + int32_t ctx_entries_len; + signed char *ctx_strings; + int32_t ctx_strings_len; }; extern __thread struct lttng_ust_jni_tls lttng_ust_context_info_tls; diff --git a/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c b/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c index 62d820b2..562da6ba 100644 --- a/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c +++ b/liblttng-ust-java-agent/jni/jul/lttng_ust_jul.c @@ -64,31 +64,39 @@ JNIEXPORT void JNICALL Java_org_lttng_ust_agent_jul_LttngJulApi_tracepointWithCo jlong millis, jint log_level, jint thread_id, - jbyteArray context_info) + jbyteArray context_info_entries, + jbyteArray context_info_strings) { jboolean iscopy; const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy); const char *logger_name_cstr = (*env)->GetStringUTFChars(env, logger_name, &iscopy); const char *class_name_cstr = (*env)->GetStringUTFChars(env, class_name, &iscopy); const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy); - signed char *context_info_array; + signed char *context_info_entries_array; + signed char *context_info_strings_array; /* * Write these to the TLS variables, so that the UST callbacks in * lttng_ust_context.c can access them. */ - context_info_array = (*env)->GetByteArrayElements(env, context_info, &iscopy); - lttng_ust_context_info_tls.ctx = (struct lttng_ust_jni_ctx *) context_info_array; - lttng_ust_context_info_tls.len = (*env)->GetArrayLength(env, context_info); + context_info_entries_array = (*env)->GetByteArrayElements(env, context_info_entries, &iscopy); + lttng_ust_context_info_tls.ctx_entries = (struct lttng_ust_jni_ctx_entry *) context_info_entries_array; + lttng_ust_context_info_tls.ctx_entries_len = (*env)->GetArrayLength(env, context_info_entries); + context_info_strings_array = (*env)->GetByteArrayElements(env, context_info_strings, &iscopy); + lttng_ust_context_info_tls.ctx_strings = context_info_strings_array; + lttng_ust_context_info_tls.ctx_strings_len = (*env)->GetArrayLength(env, context_info_strings); tracepoint(lttng_jul, event, msg_cstr, logger_name_cstr, class_name_cstr, method_name_cstr, millis, log_level, thread_id); - lttng_ust_context_info_tls.ctx = NULL; - lttng_ust_context_info_tls.len = 0; + lttng_ust_context_info_tls.ctx_entries = NULL; + lttng_ust_context_info_tls.ctx_entries_len = 0; + lttng_ust_context_info_tls.ctx_strings = NULL; + lttng_ust_context_info_tls.ctx_strings_len = 0; (*env)->ReleaseStringUTFChars(env, msg, msg_cstr); (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr); (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr); (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr); - (*env)->ReleaseByteArrayElements(env, context_info, context_info_array, 0); + (*env)->ReleaseByteArrayElements(env, context_info_entries, context_info_entries_array, 0); + (*env)->ReleaseByteArrayElements(env, context_info_strings, context_info_strings_array, 0); } diff --git a/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c b/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c index b80312e2..2537922d 100644 --- a/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c +++ b/liblttng-ust-java-agent/jni/log4j/lttng_ust_log4j.c @@ -73,7 +73,8 @@ JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LttngLog4jApi_tracepointWi jlong timestamp, jint loglevel, jstring thread_name, - jbyteArray context_info) + jbyteArray context_info_entries, + jbyteArray context_info_strings) { jboolean iscopy; const char *msg_cstr = (*env)->GetStringUTFChars(env, msg, &iscopy); @@ -82,27 +83,34 @@ JNIEXPORT void JNICALL Java_org_lttng_ust_agent_log4j_LttngLog4jApi_tracepointWi const char *method_name_cstr = (*env)->GetStringUTFChars(env, method_name, &iscopy); const char *file_name_cstr = (*env)->GetStringUTFChars(env, file_name, &iscopy); const char *thread_name_cstr = (*env)->GetStringUTFChars(env, thread_name, &iscopy); - signed char *context_info_array; + signed char *context_info_entries_array; + signed char *context_info_strings_array; /* * Write these to the TLS variables, so that the UST callbacks in * lttng_ust_context.c can access them. */ - context_info_array = (*env)->GetByteArrayElements(env, context_info, &iscopy); - lttng_ust_context_info_tls.ctx = (struct lttng_ust_jni_ctx *) context_info_array; - lttng_ust_context_info_tls.len = (*env)->GetArrayLength(env, context_info); + context_info_entries_array = (*env)->GetByteArrayElements(env, context_info_entries, &iscopy); + lttng_ust_context_info_tls.ctx_entries = (struct lttng_ust_jni_ctx_entry *) context_info_entries_array; + lttng_ust_context_info_tls.ctx_entries_len = (*env)->GetArrayLength(env, context_info_entries); + context_info_strings_array = (*env)->GetByteArrayElements(env, context_info_strings, &iscopy); + lttng_ust_context_info_tls.ctx_strings = context_info_strings_array; + lttng_ust_context_info_tls.ctx_strings_len = (*env)->GetArrayLength(env, context_info_strings); tracepoint(lttng_log4j, event, msg_cstr, logger_name_cstr, class_name_cstr, method_name_cstr, file_name_cstr, line_number, timestamp, loglevel, thread_name_cstr); - lttng_ust_context_info_tls.ctx = NULL; - lttng_ust_context_info_tls.len = 0; + lttng_ust_context_info_tls.ctx_entries = NULL; + lttng_ust_context_info_tls.ctx_entries_len = 0; + lttng_ust_context_info_tls.ctx_strings = NULL; + lttng_ust_context_info_tls.ctx_strings_len = 0; (*env)->ReleaseStringUTFChars(env, msg, msg_cstr); (*env)->ReleaseStringUTFChars(env, logger_name, logger_name_cstr); (*env)->ReleaseStringUTFChars(env, class_name, class_name_cstr); (*env)->ReleaseStringUTFChars(env, method_name, method_name_cstr); (*env)->ReleaseStringUTFChars(env, file_name, file_name_cstr); (*env)->ReleaseStringUTFChars(env, thread_name, thread_name_cstr); - (*env)->ReleaseByteArrayElements(env, context_info, context_info_array, 0); + (*env)->ReleaseByteArrayElements(env, context_info_entries, context_info_entries_array, 0); + (*env)->ReleaseByteArrayElements(env, context_info_strings, context_info_strings_array, 0); }