Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.databricks.sdk.core.logging;

/**
* Logging contract used throughout the SDK.
*
* <p>Extend this class to provide a custom logging implementation, then register it via a custom
* {@link LoggerFactory} subclass and {@link LoggerFactory#setDefault}.
*/
public abstract class Logger {

public abstract boolean isDebugEnabled();

public abstract void debug(String msg);

public abstract void debug(String format, Object... args);

public abstract void info(String msg);

public abstract void info(String format, Object... args);

public abstract void warn(String msg);

public abstract void warn(String format, Object... args);

public abstract void error(String msg);

public abstract void error(String format, Object... args);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.databricks.sdk.core.logging;

/**
* Creates and configures {@link Logger} instances for the SDK.
*
* <p>By default, logging goes through SLF4J. Users can override the backend programmatically
* before creating any SDK client:
*
* <pre>{@code
* LoggerFactory.setDefault(myCustomFactory);
* WorkspaceClient ws = new WorkspaceClient();
* }</pre>
*
* <p>Extend this class to provide a fully custom logging backend.
*/
public abstract class LoggerFactory {

private static volatile LoggerFactory defaultFactory = Slf4jLoggerFactory.INSTANCE;

/** Returns a logger for the given class, using the current default factory. */
public static Logger getLogger(Class<?> type) {
return getDefault().newInstance(type);
}

/** Returns a logger with the given name, using the current default factory. */
public static Logger getLogger(String name) {
return getDefault().newInstance(name);
}

/**
* Overrides the logging backend used by the SDK.
*
* <p>Must be called before creating any SDK client or calling {@link #getLogger}. Loggers
* already obtained will not be affected by subsequent calls.
*/
public static void setDefault(LoggerFactory factory) {
if (factory == null) {
throw new IllegalArgumentException("LoggerFactory must not be null");
}
defaultFactory = factory;
}

static LoggerFactory getDefault() {
return defaultFactory;
}

/** Creates a new logger for the given class. */
protected abstract Logger newInstance(Class<?> type);

/** Creates a new logger with the given name. */
protected abstract Logger newInstance(String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.databricks.sdk.core.logging;

/** Delegates all logging calls to an SLF4J {@code Logger}. */
class Slf4jLogger extends Logger {

private final org.slf4j.Logger delegate;

private Slf4jLogger(org.slf4j.Logger delegate) {
this.delegate = delegate;
}

static Logger create(Class<?> type) {
return new Slf4jLogger(org.slf4j.LoggerFactory.getLogger(type));
}

static Logger create(String name) {
return new Slf4jLogger(org.slf4j.LoggerFactory.getLogger(name));
}

@Override
public boolean isDebugEnabled() {
return delegate.isDebugEnabled();
}

@Override
public void debug(String msg) {
delegate.debug(msg);
}

@Override
public void debug(String format, Object... args) {
delegate.debug(format, args);
}

@Override
public void info(String msg) {
delegate.info(msg);
}

@Override
public void info(String format, Object... args) {
delegate.info(format, args);
}

@Override
public void warn(String msg) {
delegate.warn(msg);
}

@Override
public void warn(String format, Object... args) {
delegate.warn(format, args);
}

@Override
public void error(String msg) {
delegate.error(msg);
}

@Override
public void error(String format, Object... args) {
delegate.error(format, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.databricks.sdk.core.logging;

/** A {@link LoggerFactory} backed by SLF4J. This is the default. */
public class Slf4jLoggerFactory extends LoggerFactory {

public static final Slf4jLoggerFactory INSTANCE = new Slf4jLoggerFactory();

@Override
protected Logger newInstance(Class<?> type) {
return Slf4jLogger.create(type);
}

@Override
protected Logger newInstance(String name) {
return Slf4jLogger.create(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.databricks.sdk.core.logging;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

public class LoggerFactoryTest {

@AfterEach
void resetFactory() {
LoggerFactory.setDefault(Slf4jLoggerFactory.INSTANCE);
}

@Test
void defaultFactoryIsSLF4J() {
Logger logger = LoggerFactory.getLogger(LoggerFactoryTest.class);
assertNotNull(logger);
logger.info("LoggerFactory defaultFactoryIsSLF4J test message");
}

@Test
void setDefaultRejectsNull() {
assertThrows(IllegalArgumentException.class, () -> LoggerFactory.setDefault(null));
}

@Test
void getLoggerByNameWorks() {
Logger logger = LoggerFactory.getLogger("com.example.Test");
assertNotNull(logger);
logger.info("getLoggerByNameWorks test message");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.databricks.sdk.core.logging;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

public class Slf4jLoggerTest {

@Test
void createReturnsSlf4jLogger() {
Logger logger = Slf4jLogger.create(Slf4jLoggerTest.class);
assertNotNull(logger);
assertTrue(logger instanceof Slf4jLogger);
}

@Test
void slf4jLoggerOperations() {
Logger logger = Slf4jLogger.create(Slf4jLoggerTest.class);
logger.debug("debug");
logger.debug("debug {}", "arg");
logger.info("info");
logger.info("info {}", "arg");
logger.warn("warn");
logger.warn("warn {}", "arg");
logger.error("error");
logger.error("error {}", "arg");
logger.error("error {} failed", "op", new RuntimeException("cause"));
logger.isDebugEnabled();
}

}