Làm cách nào để kết quả ghi nhật ký java xuất hiện trên một dòng?


124

Tại thời điểm này, một mục nhập mặc định trông giống như sau:

Oct 12, 2008 9:45:18 AM myClassInfoHere
INFO: MyLogMessageHere

Làm cách nào để tôi thực hiện việc này?

Oct 12, 2008 9:45:18 AM myClassInfoHere - INFO: MyLogMessageHere

Làm rõ Tôi đang sử dụng java.util.logging

Câu trả lời:


81

Kể từ Java 7, java.util.logging.SimpleFormatter hỗ trợ lấy định dạng của nó từ một thuộc tính hệ thống, vì vậy việc thêm một cái gì đó như thế này vào dòng lệnh JVM sẽ khiến nó in trên một dòng:

-Djava.util.logging.SimpleFormatter.format='%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n'

Ngoài ra, bạn cũng có thể thêm cái này vào logger.properties:

java.util.logging.SimpleFormatter.format='%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n'

4
Đúng như Java7. Không có đề cập đến điều này trong tài liệu Java6.
jbruni

1
Cũng trong IDEA, hoạt động với dấu ngoặc kép. @jbruni Điều này không hoạt động trong Java6.
Joshua Davis,

1
Làm việc với các dấu ngoặc kép trong Eclipse đối với tôi.
phong phú

1
Thay vì% 1 $ tY-% 1 $ tm-% 1 $ td% 1 $ tH:% 1 $ tM:% 1 $ tS, bạn có thể viết% 1 $ tF% 1 $ tT. Làm cho nó ngắn hơn một chút. Tôi không biết nếu nó thậm chí còn nhanh hơn.
Bruno Eberhard

1
... hoặc trong logging.properties, với sự điều chỉnh dựa trên đề xuất của @BrunoEberhard và tên trình ghi rút gọn: java.util.logging.SimpleFormatter.format=%1$tF %1$tT %4$.1s %2$s %5$s%6$s%n
Kariem

73

1) -Djava.util.logging.SimpleFormatter.format

Java 7 hỗ trợ một thuộc tính với java.util.Formattercú pháp chuỗi định dạng.

-Djava.util.logging.SimpleFormatter.format=... 

Xem tại đây .

Sở thích của tôi là:

-Djava.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$-6s %2$s %5$s%6$s%n

khiến đầu ra như:

2014-09-02 16:44:57 SEVERE org.jboss.windup.util.ZipUtil unzip: Failed to load: foo.zip

2) Đưa nó vào IDE

IDE thường cho phép bạn đặt thuộc tính hệ thống cho một dự án. Ví dụ: trong NetBeans, thay vì thêm -D ... = ... ở đâu đó, hãy thêm thuộc tính trong hộp thoại hành động, ở dạng java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-...- không có bất kỳ dấu ngoặc kép nào. IDE sẽ tìm ra.

3) Đưa điều đó cho Maven - Chắc chắn

Để thuận tiện cho bạn, Đây là cách đặt nó vào Surefire:

        <!-- Surefire -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.17</version>
            <configuration>
                <systemPropertyVariables>
                    <!-- Set JUL Formatting -->
                    <java.util.logging.SimpleFormatter.format>%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$-6s %2$s %5$s%6$s%n</java.util.logging.SimpleFormatter.format>
                </systemPropertyVariables>
            </configuration>
        </plugin>

4) Làm bằng tay

Tôi có một thư viện với vài java.util.logginglớp học liên quan . Trong số đó, nó SingleLineFormatter. Có thể tải về jar tại đây .

public class SingleLineFormatter extends Formatter {

  Date dat = new Date();
  private final static String format = "{0,date} {0,time}";
  private MessageFormat formatter;
  private Object args[] = new Object[1];

  // Line separator string.  This is the value of the line.separator
  // property at the moment that the SimpleFormatter was created.
  //private String lineSeparator = (String) java.security.AccessController.doPrivileged(
  //        new sun.security.action.GetPropertyAction("line.separator"));
  private String lineSeparator = "\n";

  /**
   * Format the given LogRecord.
   * @param record the log record to be formatted.
   * @return a formatted log record
   */
  public synchronized String format(LogRecord record) {

    StringBuilder sb = new StringBuilder();

    // Minimize memory allocations here.
    dat.setTime(record.getMillis());    
    args[0] = dat;


    // Date and time 
    StringBuffer text = new StringBuffer();
    if (formatter == null) {
      formatter = new MessageFormat(format);
    }
    formatter.format(args, text, null);
    sb.append(text);
    sb.append(" ");


    // Class name 
    if (record.getSourceClassName() != null) {
      sb.append(record.getSourceClassName());
    } else {
      sb.append(record.getLoggerName());
    }

    // Method name 
    if (record.getSourceMethodName() != null) {
      sb.append(" ");
      sb.append(record.getSourceMethodName());
    }
    sb.append(" - "); // lineSeparator



    String message = formatMessage(record);

    // Level
    sb.append(record.getLevel().getLocalizedName());
    sb.append(": ");

    // Indent - the more serious, the more indented.
    //sb.append( String.format("% ""s") );
    int iOffset = (1000 - record.getLevel().intValue()) / 100;
    for( int i = 0; i < iOffset;  i++ ){
      sb.append(" ");
    }


    sb.append(message);
    sb.append(lineSeparator);
    if (record.getThrown() != null) {
      try {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        record.getThrown().printStackTrace(pw);
        pw.close();
        sb.append(sw.toString());
      } catch (Exception ex) {
      }
    }
    return sb.toString();
  }
}

tiêu thụ bộ nhớ tốt hơn so với giải pháp khác.
Tim Williscroft

Tôi đã thử điều này - nhưng nó cung cấp cho tôi nhật ký trong XML - tôi đang làm gì sai - stackoverflow.com/questions/16030578/…
user93353

nếu nó chuyển sang XML thay vì định dạng bạn mong đợi - điều đó có nghĩa là cài đặt trong tệp thuộc tính của bạn không tìm thấy lớp định dạng của bạn, bạn có thể làm 2 điều: 1. đảm bảo lớp của bạn nằm trong một gói và đặt thuộc tính định dạng thành lớp đó và gói 2. đảm bảo rằng lớp của bạn có tên duy nhất như "MyFormatter", cuối cùng: đảm bảo rằng tất cả các trình xử lý đều có định dạng bạn muốn (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter và cả: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc

Cám ơn vì đã chia sẻ. Tôi đã chia sẻ một Định dạng mà tôi đã viết để trả lời cho một câu hỏi khác . Nó thực hiện ổn đối với tôi. Tôi thích xem các thủ thuật mà các nhà phát triển khác nghĩ ra để làm cho mã nhỏ hơn và nhanh hơn.
Ryan

1
@ ondra-Žižka Vì những gì xứng đáng, tôi vừa gửi cho bạn một bản vá trên kho mã google của bạn.
Ryan

61

Tương tự như Tervor, Nhưng tôi thích thay đổi thuộc tính trong thời gian chạy.

Lưu ý rằng điều này cần được thiết lập trước khi tạo SimpleFormatter đầu tiên - như đã được viết trong phần bình luận.

    System.setProperty("java.util.logging.SimpleFormatter.format", 
            "%1$tF %1$tT %4$s %2$s %5$s%6$s%n");

6
Lưu ý rằng điều này cần được đặt trước khi tạo SimpleFormatter đầu tiên - ví dụ: trước khi nhận các trình xử lý của trình ghi nhật ký toàn cầu.
Sheepy

5
Đây là cách nhanh nhất để buộc ghi nhật ký của bạn ra một dòng mà không cần thêm bất kỳ thông số khởi động nào khác vào JVM. Nhưng hãy đảm bảo rằng bạn đã đặt thuộc tính này trước khi thực hiện lệnh gọi đến 'new SimpleFormatter ()' trong mã của mình.
Salvador Valencia

36

Giống như Obediah Stane đã nói, cần phải tạo ra formatphương pháp của riêng bạn . Nhưng tôi sẽ thay đổi một vài điều:

  • Tạo một lớp con có nguồn gốc trực tiếp từ Formatter, không phải từ SimpleFormatter. Không SimpleFormattercó gì để thêm nữa.

  • Hãy cẩn thận với việc tạo một Dateđối tượng mới ! Bạn nên đảm bảo đại diện cho ngày của LogRecord. Khi tạo mới Datevới hàm tạo mặc định, nó sẽ đại diện cho ngày và giờ các Formatterquá trình xử lý LogRecord, không phải ngày LogRecordđược tạo.

Lớp sau có thể được sử dụng như là định dạng trong một Handler, do đó có thể được thêm vào Logger. Lưu ý rằng nó bỏ qua tất cả thông tin về lớp và phương thức có sẵn trong LogRecord.

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;

public final class LogFormatter extends Formatter {

    private static final String LINE_SEPARATOR = System.getProperty("line.separator");

    @Override
    public String format(LogRecord record) {
        StringBuilder sb = new StringBuilder();

        sb.append(new Date(record.getMillis()))
            .append(" ")
            .append(record.getLevel().getLocalizedName())
            .append(": ")
            .append(formatMessage(record))
            .append(LINE_SEPARATOR);

        if (record.getThrown() != null) {
            try {
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                record.getThrown().printStackTrace(pw);
                pw.close();
                sb.append(sw.toString());
            } catch (Exception ex) {
                // ignore
            }
        }

        return sb.toString();
    }
}

Tôi đã thử điều này - nhưng nó cung cấp cho tôi nhật ký trong XML - tôi đang làm gì sai - stackoverflow.com/questions/16030578/…
user93353

nếu nó chuyển sang XML thay vì định dạng bạn mong đợi - điều đó có nghĩa là cài đặt trong tệp thuộc tính của bạn không tìm thấy lớp định dạng của bạn, bạn có thể làm 2 việc: 1. đảm bảo lớp của bạn nằm trong một gói và đặt thuộc tính định dạng thành lớp đó và gói 2. đảm bảo rằng lớp của bạn có tên duy nhất như "MyFormatter", cuối cùng: đảm bảo rằng tất cả các trình xử lý đều có định dạng bạn muốn (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter và cả: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc

10

Đây là những gì tôi đang sử dụng.

public class VerySimpleFormatter extends Formatter {

    private static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";

    @Override
    public String format(final LogRecord record) {
        return String.format(
                "%1$s %2$-7s %3$s\n",
                new SimpleDateFormat(PATTERN).format(
                        new Date(record.getMillis())),
                record.getLevel().getName(), formatMessage(record));
    }
}

Bạn sẽ nhận được một cái gì đó giống như ...

2016-08-19T17:43:14.295+09:00 INFO    Hey~
2016-08-19T17:43:16.068+09:00 SEVERE  Seriously?
2016-08-19T17:43:16.068+09:00 WARNING I'm warning you!!!

Làm thế nào chúng ta có thể có thông tin ngoại lệ đầu ra định dạng này, chẳng hạn như ngăn xếp của nó?
fegemo

1
@fegemo Tôi nghĩ bạn có thể in starcktrace như thế này. ofNullable(record.getThrown()).ifPresent(v -> v.printStackTrace());ngay trước khi trả lại tin nhắn đã định dạng.
Jin Kwon

7

Cấu hình Eclipse

Trên mỗi ảnh chụp màn hình, trong Eclipse, chọn "run as" rồi chọn "Run Configurations ..." và thêm câu trả lời từ Trevor Robinson bằng dấu ngoặc kép thay vì dấu ngoặc kép. Nếu bạn bỏ lỡ dấu ngoặc kép, bạn sẽ nhận được lỗi "không thể tìm thấy hoặc tải lớp chính".


2
Theo câu trả lời trước, điều này hoạt động trong Java 7. Java 6 không có tính năng này.
Joshua Davis

5

Tôi đã tìm ra một cách hoạt động. Bạn có thể phân lớp SimpleFormatter và ghi đè phương thức định dạng

    public String format(LogRecord record) {
        return new java.util.Date() + " " + record.getLevel() + " " + record.getMessage() + "\r\n";
    }

Một chút ngạc nhiên về API này, tôi đã nghĩ rằng nhiều chức năng / tính linh hoạt hơn sẽ được cung cấp ngay lập tức


Bất cứ ai cũng nên sử dụng formatMessage(record)hơn là record.getMessage(). Chủ sở hữu địa điểm sẽ không thay đổi.
Jin Kwon

-2

Việc ghi nhật ký này dành riêng cho ứng dụng của bạn và không phải là một tính năng chung của Java. Bạn đang chạy (các) ứng dụng nào?

Có thể điều này đến từ một thư viện ghi nhật ký cụ thể mà bạn đang sử dụng trong mã của riêng mình. Nếu vậy, vui lòng đăng chi tiết bạn đang sử dụng cái nào.


3
Nó không phải là một số ứng dụng ghi nhật ký ngẫu nhiên. Đó là của riêng javajava.util.logging.Logger
André C. Andersen

-2

Nếu bạn đăng nhập một ứng dụng web bằng tomcat, hãy thêm:

-Djava.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter

Trên các đối số VM


-3

nếu bạn đang sử dụng java.util.logging, thì có một tệp cấu hình đang thực hiện việc này để ghi nội dung (trừ khi bạn đang sử dụng cấu hình có lập trình). Vì vậy, các tùy chọn của bạn là
1) chạy bộ xử lý hậu kỳ loại bỏ các ngắt dòng
2) thay đổi cấu hình nhật ký VÀ xóa các ngắt dòng khỏi nó. Khởi động lại ứng dụng của bạn (máy chủ) và bạn sẽ tốt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.