3
votes

I am logging to Logback and have configured a Stackdriver Logging appender as follows:

<appender name="CLOUD" class="com.google.cloud.logging.logback.LoggingAppender">
    <log>application.log</log>
    <resourceType>generic_node</resourceType>
    <flushLevel>INFO</flushLevel>
</appender>

Log entries are showing up in the Stackdriver Logging console:

{
  insertId: "[...]"
  labels: {
    levelName: "INFO"
    levelValue: "20000"
  }
  logName: "[...]"
  receiveTimestamp: "2019-01-03T13:42:10.888423743Z"
  resource: {
    labels: {
      location: ""
      namespace: ""
      node_id: ""
      project_id: "[...]"
    }
    type: "generic_node"
  }
  severity: "INFO"
  textPayload: "client disconnected"
  timestamp: "2019-01-03T13:42:10.841Z"
}

However, I am missing information about the logger a log message originated from. Specifically, suppose I log a message like this:

import org.slf4j.LoggerFactory
val log = LoggerFactory.getInstance("component-a")
log.warn("temperature in hell fell below 100°C")

Then I would like to see that the log message came from the logger with the name "component-a". I found no mention of how to achieve this in the Stackdriver Logging documentation. I suppose I could configure a LoggingEnhancer to enhance every log entry with the name of the logger, but I have no information about this logger while enhancing log entries.

Is there a (hopefully "canonical") solution to this?

2
For Log Entries, you can set labels; however, I could not find any way to set labels when using LoggerFactory. I would suggest creating a feature request at at the following github link to add a feature where you can set labels when using LoggerFactory: github.com/googleapis/google-cloud-java/issuesJason

2 Answers

2
votes

This is late but I just encounter the same problem. I find the solution after checked their appender source code. You actually need implements LoggingEventEnhancer

public class StackDriverLoggingEnhancer implements LoggingEventEnhancer{
    @Override
    public void enhanceLogEntry(Builder builder, ILoggingEvent e) {
        builder.addLabel("logger", e.getLoggerName());
        builder.addLabel("thread", e.getThreadName());
    }

}

And in logback.xml

<configuration>
    <appender name="CLOUD"
        class="com.google.cloud.logging.logback.LoggingAppender">
        <resourceType>k8s_pod</resourceType>
        <loggingEventEnhancer>YOUR_PACKAGE.StackDriverLoggingEnhancer
        </loggingEventEnhancer>
        <log>application.log</log> <!-- Optional : default java.log -->
        <flushLevel>INFO</flushLevel> <!-- Optional : default ERROR -->
    </appender>
    ...
</configuration>

------UPDATED---------- The resource type should be one of the following

container
gae_app_flex
gae_app_standard
gce_instance
global

or empty (auto detection) instead of the document Google provided as of version 0.77.0-alpha

1
votes

you could just implements LogginEnhancer and references on the logback.xml file.

public class LogEnhancer implements LoggingEnhancer {

  @Override
  public void enhanceLogEntry(LogEntry.Builder logEntry) {
    logEntry.addLabel("test-label-1", "test-value-1");
  }

}

logback.xml

<configuration>
  <appender name="CLOUD" class="com.google.cloud.logging.logback.LoggingAppender">
    <!-- Optional : filter logs at or above a level -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>INFO</level>
    </filter>
    <log>application.log</log> <!-- Optional : default java.log -->
    <resourceType>gae_app</resourceType> <!-- Optional : default: auto-detected, fallback: global -->
    <enhancer>com.gentera.conversationalservices.exception.LogEnhancer</enhancer>  <!-- Optional -->
    <flushLevel>WARN</flushLevel> <!-- Optional : default ERROR -->
  </appender>

  <root level="info">
    <appender-ref ref="CLOUD" />
  </root>
</configuration>

This is an complete example on Github:

Getting Started with Stackdriver Logging using Logback