Skip to main content

Log

Python

HTTP API

The following code demonstrates a custom format, using stream for output.

from webullsdkcore.client import ApiClient
from webullsdkcore.common.region import Region

client = ApiClient(app_key="<your_app_key>", app_secret="<your_app_secret>", region_id=Region.HK.value)
log_format='%(thread)d %(asctime)s %(name)s %(levelname)s %(message)s'
client.set_stream_logger(stream=sys.stdout, format_string=log_format)

The following code demonstrates a custom format, using a file for output.

from webullsdkcore.client import ApiClient
from webullsdkcore.common.region import Region

client = ApiClient(app_key="<your_app_key>", app_secret="<your_app_secret>", region_id=Region.HK.value)
log_format='%(thread)d %(asctime)s %(name)s %(levelname)s %(message)s'
log_file_path='<my_file_path>'
client.set_file_logger(path=log_file_path, format_string=log_format)

Quotes Subscription

The following code demonstrates simple processing of log data using print through the callback function on_log.

from webullsdkmdata.quotes.subscribe.default_client import DefaultQuotesClient
from webullsdkcore.common.region import Region

quotes_client = DefaultQuotesClient("<your_app_key>", "<your_app_secret>", region_id=Region.HK.value)
def _on_log_func(client, userdata, level, log_data_buf):
print("level:%s, buf:%s" % (level, log_data_buf))
quotes_client.on_log = _on_log_func

Trade Events Subscription

The following code demonstrates simple processing of log data using print through the callback function on_log.

from webullsdktradeeventscore.events_client import EventsClient
from webullsdkcore.common.region import Region

events_client = EventsClient("<your_app_key>", "<your_app_secret>", region_id=Region.HK.value)
def _on_log_func(level, log_data_buf):
print("level:%s, buf:%s" % (level, log_data_buf))
enents_client.on_log = _on_log_func

Quotes API

The following code demonstrates a custom format, using a file for output.

from webullsdkquotescore.grpc.grpc_client import GrpcApiClient
from webullsdkcore.common.region import Region

client = GrpcApiClient(app_key="<your_app_key>", app_secret="<your_app_secret>", region_id=Region.HK.value)
log_format='%(thread)d %(asctime)s %(name)s %(levelname)s %(message)s'
log_file_path='<my_file_path>'
client.set_file_logger(path=log_file_path, format_string=log_format)

Java

Using Logging Frameworks

SDK supports for various logging frameworks by searching for the underlying logging implementation. The priority of logging frameworks: Slf4J > Log4J2 > Log4J > java.util.logging.

Example: Using Slf4J + Log4J2

Maven configuration

<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
</dependencies>

Add configuration file log4j2.properties in /resources folder. For example:

status = info

appender.console.type = Console
appender.console.name = LogToConsole
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n

appender.rolling.type = RollingFile
appender.rolling.name = LogToRollingFile
appender.rolling.fileName = logs/app.log
appender.rolling.filePattern = logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size=10MB
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 10

logger.app.name = com.webull.openapi
logger.app.level = debug
logger.app.additivity = false
logger.app.appenderRef.rolling.ref = LogToRollingFile
logger.app.appenderRef.console.ref = LogToConsole

rootLogger.level = info
rootLogger.appenderRef.stdout.ref = LogToConsole

Custom Log Implementation

To customize logger, the user can implement the interface of com.webull.openapi.logger.Logger and inherit from com.webull.openapi.logger.LoggerFactory class, for example:

Implement the Logger interface

import com.webull.openapi.logger.Logger;

public class ExampleLogger implements Logger {

private final String name;

public ExampleLogger(String name) {
this.name = name;
}

@Override
public String name() {
return name;
}

@Override
public void trace(String msg) {
System.out.println(msg);
}

@Override
public void debug(String msg) {
System.out.println(msg);
}

@Override
public void info(String msg) {
System.out.println(msg);
}

@Override
public void warn(String msg) {
System.out.println(msg);
}

@Override
public void error(String msg) {
System.out.println(msg);
}

// Omit some code...
}

Inherit from the LoggerFactory class

import com.webull.openapi.logger.Logger;
import com.webull.openapi.logger.LoggerFactory;

public class ExampleLoggerFactory extends LoggerFactory {

@Override
protected Logger newLogger(String name) {
return new ExampleLogger(name);
}
}

Set the default logger factory

public class LoggerTest {

static {
// Set the default logger factory
LoggerFactory.setDefault(new ExampleLoggerFactory());
}

private static final Logger logger = LoggerFactory.getLogger(LoggerTest.class);

public static void main(String[] args) {
logger.error("Print error log...");
logger.warn("Print warn log...");
logger.info("Print info log...");
logger.debug("Print debug log...");
logger.trace("Print trace log...");
}
}