Skip to content

Commit

Permalink
add MDC interfaces and base classes (DAT-12601) (#3567)
Browse files Browse the repository at this point in the history
Create the basic APIs for MDC in support of structured logging.
  • Loading branch information
StevenMassaro committed Dec 14, 2022
1 parent 6bc3ada commit 65eb573
Show file tree
Hide file tree
Showing 9 changed files with 457 additions and 195 deletions.
19 changes: 18 additions & 1 deletion liquibase-core/pom.xml
Expand Up @@ -283,7 +283,24 @@
</execution>
</executions>
</plugin>

<!-- Generate META-INF/services files automatically for the services specified below. -->
<plugin>
<groupId>eu.somatik.serviceloader-maven-plugin</groupId>
<artifactId>serviceloader-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<services>
<param>liquibase.logging.mdc.MdcManager</param>
</services>
</configuration>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
31 changes: 31 additions & 0 deletions liquibase-core/src/main/java/liquibase/Beta.java
@@ -0,0 +1,31 @@
package liquibase;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Signifies that a public API (public class, method or field) is subject to incompatible changes,
* or even removal, in a future release. An API bearing this annotation is exempt from any
* compatibility guarantees made by its containing library. Note that the presence of this
* annotation implies nothing about the quality or performance of the API in question, only the fact
* that it is not "API-frozen."
*
* <p>It is generally safe for <i>applications</i> to depend on beta APIs, at the cost of some extra
* work during upgrades. However it is generally inadvisable for <i>libraries</i> (which get
* included on users' CLASSPATHs, outside the library developers' control) to do so.
*
* @author Kevin Bourrillion
*/
@Retention(RetentionPolicy.CLASS)
@Target({
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.FIELD,
ElementType.METHOD,
ElementType.TYPE
})
@Documented
public @interface Beta {}
51 changes: 49 additions & 2 deletions liquibase-core/src/main/java/liquibase/Scope.java
Expand Up @@ -7,17 +7,20 @@
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.listener.LiquibaseListener;
import liquibase.logging.LogService;
import liquibase.logging.Logger;
import liquibase.logging.*;
import liquibase.logging.core.JavaLogService;
import liquibase.logging.core.LogServiceFactory;
import liquibase.logging.mdc.MdcManager;
import liquibase.logging.mdc.MdcManagerFactory;
import liquibase.logging.mdc.MdcObject;
import liquibase.osgi.Activator;
import liquibase.resource.ClassLoaderResourceAccessor;
import liquibase.resource.ResourceAccessor;
import liquibase.servicelocator.ServiceLocator;
import liquibase.servicelocator.StandardServiceLocator;
import liquibase.ui.ConsoleUIService;
import liquibase.ui.UIService;
import liquibase.util.CollectionUtil;
import liquibase.util.SmartMap;
import liquibase.util.StringUtil;

Expand Down Expand Up @@ -64,6 +67,7 @@ public enum Attr {
private Scope parent;
private SmartMap values = new SmartMap();
private String scopeId;
private static final Map<String, List<MdcObject>> addedMdcEntries = new HashMap<>();

private LiquibaseListener listener;

Expand Down Expand Up @@ -230,6 +234,12 @@ public static void exit(String scopeId) throws Exception {
throw new RuntimeException("Cannot end scope " + scopeId + " when currently at scope " + currentScope.scopeId);
}

// clear the MDC values added in this scope
List<MdcObject> mdcObjects = addedMdcEntries.get(currentScope.scopeId);
for (MdcObject mdcObject : CollectionUtil.createIfNull(mdcObjects)) {
mdcObject.close();
}

scopeManager.setCurrentScope(currentScope.getParent());
}

Expand Down Expand Up @@ -377,6 +387,43 @@ public Charset getFileEncoding() {
return get(Attr.fileEncoding, Charset.defaultCharset());
}

/**
* Get the current MDC manager.
*/
public MdcManager getMdcManager() {
MdcManagerFactory mdcManagerFactory = getSingleton(MdcManagerFactory.class);
return mdcManagerFactory.getMdcManager();
}

/**
* Add a key value pair to the MDC using the MDC manager. This key value pair will be automatically removed from the
* MDC when this scope exits.
*/
public MdcObject addMdcValue(String key, String value) {
return addMdcValue(key, value, true);
}

/**
* Add a key value pair to the MDC using the MDC manager.
* @param removeWhenScopeExits if true, this key value pair will be automatically removed from the MDC when this
* scope exits. If there is not a demonstrable reason for setting this parameter to false
* then it should be set to true.
*/
public MdcObject addMdcValue(String key, String value, boolean removeWhenScopeExits) {
MdcObject mdcObject = getMdcManager().put(key, value);
if (removeWhenScopeExits) {
Scope currentScope = getCurrentScope();
String scopeId = currentScope.scopeId;
if (addedMdcEntries.containsKey(scopeId)) {
addedMdcEntries.get(scopeId).add(mdcObject);
} else {
addedMdcEntries.put(scopeId, new ArrayList<>(Collections.singletonList(mdcObject)));
}
}

return mdcObject;
}

/**
* Returns {@link LiquibaseListener}s defined in this scope and/or all its parents that are of the given type.
*/
Expand Down

0 comments on commit 65eb573

Please sign in to comment.