Skip to content

Log API Improvements #974

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c6c58e5
Add custom JSON logging support with unescaped `data` and plain `mess…
mrodbratschi Jun 5, 2025
0390aff
Restore some changes
mrodbratschi Jun 6, 2025
9fe1f5d
New methods added
mrodbratschi Jun 12, 2025
5757ac4
A custom resolver is added to handle messages other than MapMessages …
mrodbratschi Jun 18, 2025
1434503
Add a custom .json template that uses the custom resolver
mrodbratschi Jun 18, 2025
019dd90
Refactoring
mrodbratschi Jun 18, 2025
87c7b43
Fix cyclic referencing of gxClassR
mrodbratschi Jun 26, 2025
fb92557
Merge branch 'master' into feature/log-improvement
mrodbratschi Jun 26, 2025
466e167
Fix: AndroidLogger is not abstract and does not override abstract met…
mrodbratschi Jun 26, 2025
d9bf16e
Merge branch 'feature/log-improvement' of https://github.com/genexusl…
mrodbratschi Jun 26, 2025
ca17eb5
Fix: AndroidLogger is not abstract and does not override abstract met…
mrodbratschi Jun 26, 2025
4c6e64c
Remove unnecessary comment
mrodbratschi Jun 30, 2025
bce840b
Avoid code duplication
mrodbratschi Jun 30, 2025
f5a2d66
Uses org.json instead of Gson
mrodbratschi Jul 1, 2025
9cc80d0
Remove casting
mrodbratschi Jul 1, 2025
ebb9788
Ensure type safety
mrodbratschi Jul 1, 2025
018e64e
Move it to the resources folder. When compiling it will be in the roo…
mrodbratschi Jul 1, 2025
dd7a0f8
Rename constant to WARN
mrodbratschi Jul 1, 2025
940f24a
Explicitly prevent instantiation
mrodbratschi Jul 1, 2025
3381ea9
Plugin rename
mrodbratschi Jul 1, 2025
89380c4
Build the message only if the loglevel is enabled
mrodbratschi Jul 2, 2025
49b138d
Check if the log format is JSON once.
mrodbratschi Jul 2, 2025
70e2f65
Filters the stack trace to ignore the first lines called from this pa…
mrodbratschi Jul 2, 2025
33f00db
Refactoring
mrodbratschi Jul 2, 2025
569f8a3
Merge branch 'master' into feature/log-improvement
mrodbratschi Jul 2, 2025
c26b06e
Merge branch 'master' into feature/log-improvement
mrodbratschi Jul 3, 2025
15dcce7
Maintain insertion order when logging JSONs
mrodbratschi Jul 9, 2025
c9e9a2f
Merge branch 'master' into feature/log-improvement
mrodbratschi Jul 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 21 additions & 24 deletions common/src/main/java/com/genexus/diagnostics/Log.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,60 @@ public class Log {
private static ILogger getLogger() {
return getLogger("");
}

public static ILogger getMainLogger() {
return LogManager.getLogger("com.genexus.logging");
}

private static ILogger getLogger(String topic) {
ILogger log;
if (topic != null && topic.length() > 0) {
log = LogManager.getLogger(topic);
}
else {
} else {
log = getMainLogger();
}
return log;
}

public static void write(int logLevel, String message, String topic) {
write(message, topic, logLevel);
}

public static void write(String message, String topic, int logLevel) {
ILogger log = getLogger(topic);

switch (logLevel) {
case LogLevel.OFF: //LogLevel off
LogLevel level = LogLevel.fromInt(logLevel);

switch (level) {
case OFF: //LogLevel off
break;
case LogLevel.TRACE:
case TRACE:
log.trace(message);
break;
case LogLevel.DEBUG:
log.debug(message);
break;
case LogLevel.INFO:
case INFO:
log.info(message);
break;
case LogLevel.WARNING:
case WARN:
log.warn(message);
break;
case LogLevel.ERROR:
case ERROR:
log.error(message);
break;
case LogLevel.FATAL:
case FATAL:
log.fatal(message);
break;
default:
log.debug(message);
}
log.debug(message);
}
}

public static void write(String message) {
getLogger().debug(message);
}

public static void write(String message, String topic) {
getLogger(topic).debug(message);
}

public static void error(String message) {
getLogger().error(message);
}
Expand All @@ -87,7 +84,7 @@ public static void fatal(String message, String topic) {
public static void fatal(String message, String topic, Throwable ex) {
getLogger(topic).fatal(message, ex);
}

public static void warning(String message) {
getLogger().warn(message);
}
Expand Down Expand Up @@ -115,7 +112,7 @@ public static void debug(String message) {
public static void debug(String message, String topic) {
getLogger(topic).debug(message);
}

public static void debug(String message, String topic, Throwable ex) {
getLogger(topic).debug(message, ex);
}
Expand Down
32 changes: 21 additions & 11 deletions common/src/main/java/com/genexus/diagnostics/LogLevel.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package com.genexus.diagnostics;

public class LogLevel {

static final int OFF = 0;
static final int TRACE = 1;
static final int DEBUG = 5;
static final int INFO = 10;
static final int WARNING = 15;
static final int ERROR = 20;
static final int FATAL = 30;


public enum LogLevel {
OFF(0),
TRACE(1),
DEBUG(5),
INFO(10),
WARN(15),
ERROR(20),
FATAL(30);

private final int lvl;
LogLevel(int lvl) { this.lvl = lvl; }
public int intValue() { return lvl; }

public static LogLevel fromInt(int lvl) {
for (LogLevel level : LogLevel.values()) {
if (level.intValue() == lvl) {
return level;
}
}
return LogLevel.OFF;
}
}
72 changes: 58 additions & 14 deletions common/src/main/java/com/genexus/diagnostics/UserLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,34 @@ public static ILogger getMainLogger() {
private static ILogger getLogger(String topic) {
ILogger log;
if (topic != null && topic.length() > 0) {
String loggerName = topic.startsWith("$") ? topic.substring(1): String.format("%s.%s", defaultUserLogNamespace, topic.trim());
String loggerName = topic.startsWith("$") ? topic.substring(1) : String.format("%s.%s", defaultUserLogNamespace, topic.trim());
log = LogManager.getLogger(loggerName);
}
else {
} else {
log = getMainLogger();
}
return log;
}

public static void write( int logLevel, String message, String topic) {
public static void write(int logLevel, String message, String topic) {
ILogger log = getLogger(topic);
LogLevel level = LogLevel.fromInt(logLevel);

switch (logLevel) {
case LogLevel.OFF: //LogLevel off
switch (level) {
case OFF: //LogLevel off
break;
case LogLevel.TRACE:
case TRACE:
log.trace(message);
break;
case LogLevel.DEBUG:
log.debug(message);
break;
case LogLevel.INFO:
case INFO:
log.info(message);
break;
case LogLevel.WARNING:
case WARN:
log.warn(message);
break;
case LogLevel.ERROR:
case ERROR:
log.error(message);
break;
case LogLevel.FATAL:
case FATAL:
log.fatal(message);
break;
default:
Expand Down Expand Up @@ -120,4 +117,51 @@ public static void debug(String message, String topic) {
public static void debug(String message, String topic, Throwable ex) {
getLogger(topic).debug(message, ex);
}

public static void setContext(String key, Object value) {
// Topic is ignored, also if you put something
getLogger("$").setContext(key, value);
}

public static void write(String message, String topic, int logLevel, Object data, boolean stackTrace) {
getLogger(topic).write(message, logLevel, data, stackTrace);
}

public static void write(String message, String topic, int logLevel, Object data) {
write(message, topic, logLevel, data, false);
}

public static boolean isDebugEnabled() {
return getLogger().isDebugEnabled();
}

public static boolean isErrorEnabled() {
return getLogger().isErrorEnabled();
}

public static boolean isFatalEnabled() {
return getLogger().isFatalEnabled();
}

public static boolean isInfoEnabled() {
return getLogger().isInfoEnabled();
}

public static boolean isWarnEnabled() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your level constant is called WARNING, but the method is isWarnEnabled(). It’s better if the naming matches exactly (e.g. either rename the constant to WARN or the method to isWarningEnabled())

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return getLogger().isWarnEnabled();
}

public static boolean isTraceEnabled() {
return getLogger().isTraceEnabled();
}

public static boolean isEnabled(int logLevel) {
return getLogger().isEnabled(logLevel);
}

public static boolean isEnabled(int logLevel, String topic) {
return getLogger(topic).isEnabled(logLevel);
}


}
33 changes: 23 additions & 10 deletions common/src/main/java/com/genexus/diagnostics/core/ILogger.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
package com.genexus.diagnostics.core;

public interface ILogger {

void fatal(String msg, Throwable ex);

void fatal(String msg1, String msg2, Throwable ex);

void fatal(Throwable ex, String[] list);

void fatal(String[] list);

void fatal(String msg);

void error(String msg, Throwable ex);

void error(String msg1, String msg2, Throwable ex);

void error(Throwable ex, String[] list);

void error(String[] list);

void error(String msg);

void warn(String msg);

void warn(Throwable ex, String[] list);

void warn(String[] list);

void warn(String msg, Throwable ex);

void debug(String msg);

void debug(Throwable ex, String[] list);

void debug(String[] list);
Expand All @@ -41,19 +41,19 @@ public interface ILogger {
void debug(String msg, Throwable ex);

void info(String[] list);

void info(String msg);

void trace(String msg);

void trace(Throwable ex, String[] list);

void trace(String[] list);

void trace(String msg1, String msg2, Throwable ex);

void trace(String msg, Throwable ex);

boolean isDebugEnabled();

boolean isErrorEnabled();
Expand All @@ -65,5 +65,18 @@ public interface ILogger {
* msg); } }
*/


default void setContext(String key, Object value) {}

default void write(String message, int logLevel, Object data, boolean stackTrace) {}

default boolean isFatalEnabled() { return false; }

default boolean isWarnEnabled() { return false; }

default boolean isInfoEnabled() { return false; }

default boolean isTraceEnabled() { return false; }

default boolean isEnabled(int logLevel) { return false; }

}
9 changes: 7 additions & 2 deletions wrappercommon/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,13 @@
<groupId>org.apache.ws.security</groupId>
<artifactId>wss4j</artifactId>
<version>1.6.19</version>
</dependency>
</dependencies>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-layout-template-json</artifactId>
<version>2.24.3</version>
</dependency>
</dependencies>

<build>
<finalName>gxwrappercommon</finalName>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.genexus.diagnostics.core.provider;

import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext;
import org.apache.logging.log4j.layout.template.json.resolver.EventResolverFactory;
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverConfig;
import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverFactory;


@Plugin(name = "CustomMessage", category = TemplateResolverFactory.CATEGORY)
public final class CustomMessageFactory implements EventResolverFactory {
private static final CustomMessageFactory INSTANCE = new CustomMessageFactory();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now you have a package-private default constructor (implicit), plus a single INSTANCE. It’s clearer to readers if you explicitly prevent instantiation

private static final CustomMessageFactory INSTANCE = new CustomMessageFactory();
private CustomMessageFactory() { /* no instances */ }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private CustomMessageFactory() { /* no instances */ }

@PluginFactory
public static CustomMessageFactory getInstance() {
return INSTANCE;
}

@Override
public String getName() {
return CustomMessageResolver.getName();
}

@Override
public CustomMessageResolver create(EventResolverContext context, TemplateResolverConfig config) {
return new CustomMessageResolver(config);
}
}
Loading
Loading