> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Logging from Java

export const VersionRequirements = ({versions = []}) => {
  if (!Array.isArray(versions) || versions.length === 0) {
    return null;
  }
  const boundaries = {
    upper: " or lower",
    exact: "",
    lower: " or higher"
  };
  const containerStyle = {
    marginTop: "0.5rem",
    marginBottom: "1.5rem"
  };
  const lineStyle = {
    display: "block",
    margin: "0 0 0.35rem 0",
    fontSize: "0.875rem",
    lineHeight: "1.4"
  };
  const pillBaseStyle = {
    display: "inline-block",
    padding: "0.1em 0.4em",
    borderRadius: "0.25rem",
    border: "1px solid",
    fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
    fontSize: "0.85em",
    fontWeight: 500
  };
  const pillColors = {
    "AppSignal for Elixir": {
      background: "#f3e8ff",
      borderColor: "#e9d5ff",
      color: "#9333ea"
    },
    "AppSignal for Front-end": {
      background: "#fef9c3",
      borderColor: "#fde68a",
      color: "#ca8a04"
    },
    "AppSignal for Go": {
      background: "#ccfbf1",
      borderColor: "#99f6e4",
      color: "#0d9488"
    },
    "AppSignal for JavaScript": {
      background: "#fef9c3",
      borderColor: "#fde68a",
      color: "#ca8a04"
    },
    "AppSignal for Node.js": {
      background: "#dcfce7",
      borderColor: "#bbf7d0",
      color: "#16a34a"
    },
    "AppSignal for Python": {
      background: "#dbeafe",
      borderColor: "#bfdbfe",
      color: "#2563eb"
    },
    "AppSignal for Ruby": {
      background: "#fee2e2",
      borderColor: "#fecaca",
      color: "#dc2626"
    },
    "AppSignal for Rust": {
      background: "#ffedd5",
      borderColor: "#fed7aa",
      color: "#ea580c"
    }
  };
  const defaultPillColor = {
    background: "#f4f4f5",
    borderColor: "#e4e4e7",
    color: "#52525b"
  };
  const getPillStyle = name => ({
    ...pillBaseStyle,
    ...pillColors[name] || defaultPillColor
  });
  const getBoundText = bound => {
    return boundaries[bound] || boundaries.lower;
  };
  return <div style={containerStyle}>
      {versions.map((v, i) => <p key={`${v.name}-${v.version}-${v.bound || "lower"}-${i}`} style={lineStyle}>
          This feature requires{" "}
          <code style={getPillStyle(v.name)}>{v.name}</code> version {v.version}
          {getBoundText(v.bound)}.
        </p>)}
    </div>;
};

<VersionRequirements
  versions={[
{ name: "AppSignal Collector", version: "0.7.0" }
]}
/>

This documentation outlines how to configure logging with the AppSignal for Java integration.

## Configure Logging

<Warning>
  🔐 Do not send <strong>Personal Identifiable Information (PII)</strong> to AppSignal. Filter PII (e.g., names, emails) from logs and use an ID, hash, or pseudonymized identifier instead. <br /> <br /> For **HIPAA-covered entities**, more information about signing a Business Associate Agreement (BAA) can be found in our [Business Add-Ons documentation](/support/business-add-ons).
</Warning>

You do not need to create a log source to send logs from the AppSignal for Java integration. An "application" log source will be created automatically.

The Java integration uses OpenTelemetry's logging capabilities to send logs to AppSignal.

### Stand-alone usage

To use logging with OpenTelemetry in Java, you need to set up the logger using the OpenTelemetry LoggerProvider.

<CodeGroup>
  ```java Java theme={null}
  import io.opentelemetry.api.GlobalOpenTelemetry;
  import io.opentelemetry.api.logs.Logger;
  import io.opentelemetry.api.logs.LoggerProvider;
  import io.opentelemetry.api.logs.Severity;

  public class MyApplication {
      public void logMessages() {
          // Get the logger from the global logger provider
          LoggerProvider loggerProvider = GlobalOpenTelemetry.getLoggerProvider();
          Logger logger = loggerProvider.get("my-app");

          // Log a message
          logger.logRecordBuilder()
              .setSeverity(Severity.INFO)
              .setBody("Log message line")
              .emit();
      }
  }
  ```
</CodeGroup>

### Usage with Log4j

Log4j is automatically instrumented by the OpenTelemetry Java agent. Logs emitted using Log4j2
will automatically be sent to AppSignal.

Context added using `ThreadContext` or within `StructuredDataMessage` logs will be shown as
log tags in AppSignal.

<CodeGroup>
  ```java Java theme={null}
  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.ThreadContext;
  import org.apache.logging.log4j.message.StructuredDataMessage;

  public class MyService {
      private static final Logger logger = LogManager.getLogger(MyService.class);

      public void processOrder(String orderId) {
          // This will be shown as a tag in AppSignal for all log lines
          ThreadContext.put("order_id", orderId);

          logger.info("Processing order");

          StructuredDataMessage structuredMessage = new StructuredDataMessage(
              "processing_items", // ID (not shown in AppSignal)
              String.format("Processing items in order"), // Message
              "order" // Type (not shown in AppSignal)
          );

          // This will be shown as a tag in AppSignal for this log line
          structuredMessage.put("item_count", 123);
          logger.info(structuredMessage);

          ThreadContext.clearAll();
      }
  }
  ```
</CodeGroup>

### Usage with `java.util.logging`

Java's built-in logging framework, `java.util.logging`, is automatically instrumented by the
OpenTelemetry Java agent. Logs emitted using `java.util.logging` will automatically be sent to
AppSignal.

<CodeGroup>
  ```java Java theme={null}
  import java.util.logging.Logger;
  import java.util.logging.Level;

  public class MyApplication {
      private static final Logger logger = Logger.getLogger(MyApplication.class.getName());

      public void doSomething() {
          logger.info("Application started");
          logger.log(Level.WARNING, "This is a warning message");
          logger.severe("This is an error message");
      }
  }
  ```
</CodeGroup>

## Usage

### Sending Logs

Using the OpenTelemetry logger directly, you can define the severity level of your logs:

<CodeGroup>
  ```java Java theme={null}
  import io.opentelemetry.api.GlobalOpenTelemetry;
  import io.opentelemetry.api.logs.Logger;
  import io.opentelemetry.api.logs.LoggerProvider;
  import io.opentelemetry.api.logs.Severity;

  public class MyApplication {
      public void sendLogs() {
          // Get the logger from the global logger provider
          LoggerProvider loggerProvider = GlobalOpenTelemetry.getLoggerProvider();
          Logger logger = loggerProvider.get("my-app");

          // Different severity levels
          logger.logRecordBuilder()
              .setSeverity(Severity.WARN)
              .setBody("Something went wrong")
              .emit();

          logger.logRecordBuilder()
              .setSeverity(Severity.INFO)
              .setBody("Action completed successfully")
              .emit();

          logger.logRecordBuilder()
              .setSeverity(Severity.ERROR)
              .setBody("Database connection failed")
              .emit();
      }
  }
  ```
</CodeGroup>

You can define custom attributes to send log information that can be used when filtering and querying logs:

<CodeGroup>
  ```java Java theme={null}
  import io.opentelemetry.api.GlobalOpenTelemetry;
  import io.opentelemetry.api.common.AttributeKey;
  import io.opentelemetry.api.common.Attributes;
  import io.opentelemetry.api.logs.Logger;
  import io.opentelemetry.api.logs.LoggerProvider;
  import io.opentelemetry.api.logs.Severity;

  public class InvoiceService {
      public void generateInvoice(Customer customer) {
          LoggerProvider loggerProvider = GlobalOpenTelemetry.getLoggerProvider();
          Logger logger = loggerProvider.get("invoice_helper");

          logger.logRecordBuilder()
              .setSeverity(Severity.INFO)
              .setBody("Generating invoice for customer")
              .setAllAttributes(Attributes.of(
                  AttributeKey.stringKey("customer_id"), customer.getId()
              ))
              .emit();
      }
  }
  ```
</CodeGroup>

You can query and filter on message contents and attribute values from within the [Log Management](/logging/log-management) tool.

Once configured, the desired attributes will be sent to AppSignal as log tags, and be queryable in the AppSignal logging interface.

## Filtering Logs

You can use [the `ignore_logs` configuration option](/java/configuration#option-ignore_logs) to ignore log lines. See [our Ignore Logs guide](/guides/filter-data/ignore-logs) to learn more.

## Need Help?

After configuring your Java application to send logs, logs should appear in AppSignal. If you are unsure about this step or AppSignal is not receiving any logs, you can always [reach out](mailto:support@appsignal.com) for assistance. We'll help get you back on track!
