Recipe Name:
SLF4J Logging: System.err
Description:
Replace System.err.print.* with consistent SLF4J error logging
Level:
marked_information
Language:
  • java
Tags:
  • SLF4J
  • framework specific
  • logging
  • quality
Documentation

The system's PrintStream's should not be used for logging purposes. Instead replace them with consistent SLF4J error logging.

SLF4J provides a simple facade for various logging frameworks allowing them to be plugged in at deployment time. It also comes with specific methods for the different log levels.

Before
 public void printMessages(Throwable e) {
    System.out.println(e.getMessage());
    System.out.print(e.getMessage());
    System.err.println(e.getMessage());
    System.err.print(e.getMessage());
}
After
private final static org.slf4j.Logger Logger = org.slf4j.LoggerFactory.getLogger(LoggingExample.class);

public void printMessages(Throwable e) {
    Logger.debug(e.getMessage());
    Logger.error(e.getMessage());
    Logger.info(e.getMessage());
    Logger.warn(e.getMessage());
}
References
Recipe
id: scw:logging:slf4j:System.err_consistent_logging
version: 10
metadata:
  name: 'SLF4J Logging: System.err'
  shortDescription: Replace System.err.print.* with consistent SLF4J error logging
  level: marked_information
  language: java
  scwCategory: insufficient_logging:generic
  cweCategory: 778
  enabled: true
  descriptionFile: descriptions/Consistent_SLF4J_logging.html
  tags: SLF4J;framework specific;logging;quality
search:
  methodcall:
    in:
      typeDeclaration:
        anyOf:
        - with:
            child:
              field:
                name: logger
                type: org.slf4j.Logger
        - without:
            child:
              field:
                name: logger
                type:
                  reference:
                    not: org.slf4j.Logger
                  checkInheritance: true
    name:
      matches: print.*
    declaration:
      type: java.io.PrintStream
    "on":
      reference:
        name: err
availableFixes:
- name: ' [RECOMMENDED] Replace System.err with SLF4J error function'
  actions:
  - rewrite:
      to: logger.error({{{ arguments }}})
      target: self
  - addField:
      field: private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger({{{ containingClass.containingClass.name }}}.class);
      target: parentClass
- name: '[OPTIONAL] Replace System.err with SLF4J debug function'
  actions:
  - rewrite:
      to: logger.debug({{{ arguments }}})
      target: self
  - addField:
      field: private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger({{{ containingClass.containingClass.name }}}.class);
      target: parentClass
- name: '[OPTIONAL] Replace System.err with SLF4J info function'
  actions:
  - rewrite:
      to: logger.info({{{ arguments }}})
      target: self
  - addField:
      field: private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger({{{ containingClass.containingClass.name }}}.class);
      target: parentClass
- name: '[OPTIONAL] Replace System.err with SLF4J warn function'
  actions:
  - rewrite:
      to: logger.warn({{{ arguments }}})
      target: self
  - addField:
      field: private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger({{{ containingClass.containingClass.name }}}.class);
      target: parentClass
- name: '[OPTIONAL] Replace System.err with SLF4J trace function'
  actions:
  - rewrite:
      to: logger.trace({{{ arguments }}})
      target: self
  - addField:
      field: private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger({{{ containingClass.containingClass.name }}}.class);
      target: parentClass