2012-11-18 29 views
18

Gần đây tôi đang viết một số mã điểm chuẩn vi mô, vì vậy tôi phải in ra các hành vi JVM cùng với thông tin điểm chuẩn của tôi. Tôi sử dụngLàm thế nào để chuyển hướng đầu ra JVM mà không xé đầu ra khỏi ứng dụng?

-XX:+PrintCompilation 
-XX:+PrintGCDetails 

và các tùy chọn khác để nhận trạng thái JVM. Đối với thông tin điểm chuẩn, tôi chỉ cần sử dụng phương thức System.out.print(). Vì tôi cần biết thứ tự của thông điệp tôi đã in và đầu ra JVM.

Tôi có thể nhận được kết quả tốt khi tôi chỉ in chúng ra trong bảng điều khiển, mặc dù đầu ra JVM đôi khi xé thông điệp của tôi lên, nhưng vì chúng nằm trong các chủ đề khác nhau, nó là dễ hiểu và chấp nhận được.

Khi tôi cần phải làm một số tiêu chuẩn lô, tôi muốn redirect the output into a file với pipe (> in Linux system), và sử dụng python để có được những kết quả từ các tập tin và phân tích nó.

Đây là vấn đề:

The JVM output always overlapped with the messages I printed in the Java application. Nó hủy hoại hoàn thành các thông điệp.

Bất kỳ ý tưởng nào về cách xử lý tình huống này? Tôi cần both the JVM output and application output in the same place in order to preserve the sequence because it is important. And they do not overlap on each other so I don't lose anything.

Trả lời

9

tôi sẽ đề nghị tham gia một đường vòng nhẹ và xem xét sử dụng Java Instrumentation API - sử dụng (ghi) một cách đơn giản Java Agent để làm điều này. Từ quan điểm điểm chuẩn của bạn, điều này sẽ cung cấp cho bạn nhiều quyền lực hơn là tốt. Bạn có thể sử dụng Java Agent của bạn để ghi lại mọi thứ (và do đó sẽ không có sự tranh chấp giữa các luồng logger khác nhau).

Bạn có thể đọc thêm tại http://www.javabeat.net/2012/06/introduction-to-java-agents/ hoặc http://today.java.net/pub/a/today/2008/04/24/add-logging-at-class-load-time-with-instrumentation.html

+0

Ý tưởng hay, tôi đã cố gắng chuyển hướng stdout và stderr trong tác nhân, tôi có thể chuyển hướng đầu ra từ mã java của tôi, nhưng đầu ra JVM không được chuyển hướng. Và phương pháp được giới thiệu trong bài viết bạn đã đề cập - sửa đổi mã byte khi tải lớp, tôi phải biết JVM đã gọi ra gì khi nó xuất thông tin, sau đó có thể tôi sửa đổi nó, nhưng tôi không có loại đó thông tin, bạn có gợi ý gì không? – dawnstar

0

tôi sẽ đề nghị để thử những điều sau đây. Đây là một hack và sẽ yêu cầu một số tinkering. Nhưng nắm vững cách tiếp cận này có lẽ sẽ trả hết trong một thời gian dài. Đặc biệt, nếu bạn làm rất nhiều điểm chuẩn.

Có nói rằng tôi tích cực rằng HS (ngày nay, Oracle) nên có một tùy chọn để chuyển hướng đầu ra trình biên dịch sang một tệp. Bạn chỉ cần tìm nó đủ cứng :-) HS nên có một tùy chọn để in ra tất cả các tùy chọn JVM và trình biên dịch của họ và trong số đó có thể là một trong đó chuyển hướng đầu ra đến một tập tin.

Anyways, tôi digressed ...

1) Nên có src.zip trong $ JAVA_HOME của bạn hoặc% JAVA_HOME%. Nó chứa mã nguồn cho Thư viện lớp Java.

2) Sửa đổi System.out để chuyển hướng tất cả đầu ra đến một lỗi cụ thể hoặc chỉ đơn giản là làm cho nó chèn một số ký hiệu đặc biệt mà bạn có thể grep để nắm bắt stdout và stderr. Thật không may, tôi không thể cụ thể hơn với bước cụ thể này, vì chính sách của công ty chúng tôi cấm chúng tôi kiểm tra nội dung của src.zip. Tôi chỉ có thể tưởng tượng bước này khó khăn như thế nào. Có lẽ nó là tầm thường như trao đổi "ra" với dòng đầu ra của bạn hoặc khó khăn như sửa đổi mọi phương pháp in duy nhất mà ứng dụng của bạn sử dụng trực tiếp. Tôi thậm chí không biết có bao nhiêu người bản xứ System.out sử dụng

3) Đặt phiên bản đã biên dịch của bạn vào tệp jar.

4) Thêm tùy chọn này vào dòng lệnh của bạn: -Xbootclasspath/p: full_path_to_your_jar Điều này sẽ báo cho JVM sử dụng phiên bản của bạn trước tiên. "P" là viết tắt của phần thêm.

Hy vọng rằng đây sẽ giúp ...

5

Hãy thử sử dụng System.out.println() thay vì System.out.print(). System.out.println() buộc luồng tuôn ra bên trong phần được đồng bộ hóa và ít nhất đầu ra của bạn sẽ không bị lẫn lộn.

0

Trước tiên, tôi sẽ thử những gì @barracel lưu ý về việc sử dụng System.out.println().

Tôi không biết nhiều về Java, nhưng bạn cũng có thể viết ra tất cả các thông báo gỡ lỗi của bạn để stderr và để lại stdout cho JVM. Điều này có thể ngăn chặn sự ô nhiễm của stdout đó là dường như xảy ra khi nhiều chủ đề ghi vào cùng một bộ mô tả tập tin.

0

Thử tách đầu ra của JVM và ứng dụng của bạn. thông tin

  • Output JVM để stdout
  • Output thông tin ứng dụng của bạn để thiết bị lỗi chuẩn, với "System.err.println()"
  • Phân tích đầu ra với các công cụ yêu thích của bạn.

Vì vậy, dòng lệnh là như thế này:

$java -XX:+PrintCompilation -XX:+PrintGCDetails MainClass 1>stdout.txt 2>stderr.txt 
5

Sử dụng Log4J hoặc khai thác gỗ khung message-driven so System.out.println().

Log4J sử dụng mô hình sự kiện tin nhắn đảm bảo sắp xếp các tin nhắn. Hơn nữa, các 'appender' khác nhau có thể được sử dụng để đăng nhập vào cơ sở dữ liệu hoặc đầu ra/tập tin khác, cho phép phân tách bằng gói Java và các thuộc tính khác để dữ liệu không bị lẫn lộn.

Ngoài ra, dọc theo các dòng này, hãy xem xét sử dụng bộ hẹn giờ hiệu suất cao và/hoặc không cố gắng đo lường các sự kiện rất ngắn (mili giây). Lý do là một cuộc gọi đến System.currentTimeMillis() sẽ chỉ lần lượt gọi đồng hồ hệ điều hành. Trên mọi hệ điều hành, có một số 'trôi dạt đồng hồ' và bộ đệm ẩn tiếp tục sao cho chức năng hệ thống bên dưới có thể trả lại cùng một giá trị, dẫn đến khoảng thời gian +/- 30 ms trong thời gian thực tế. Để khắc phục điều này hoặc tăng độ chính xác, hãy nhóm các chức năng được đo thành kích thước mẫu đủ lớn và sau đó chia cho số lần lặp lại.

Ví dụ: thực hiện 10K hoạt động trung bình 1-2 mili giây là một hoạt động được đo. Sau đó chia cho 10K để có được thời gian cho mỗi hoạt động.

Nếu không, một lần nữa, bộ hẹn giờ hiệu suất cao sẽ là cần thiết.

+0

Điều này không trả lời câu hỏi gốc. Log4J không hỗ trợ nhật ký chẩn đoán HotSpot hoặc vấn đề xen kẽ chúng trong cùng một tệp với đầu ra của ứng dụng theo cách phản ánh mối quan hệ thời gian của chúng. –

+0

Chẩn đoán HotSpot không được đề cập trong câu hỏi. Câu hỏi đặt ra là làm thế nào để bảo tồn chuỗi đăng nhập mà không cần chồng chéo và giải pháp chắc chắn là một cách để thực hiện nó. –

+0

Câu hỏi (khi tôi đọc nó, nó đã được chỉnh sửa) đề cập đến chẩn đoán HotSpot, như -XX: + PrintCompilation, và cần phải sắp xếp chúng một cách chính xác với việc ghi nhật ký khác, trong đoạn đầu tiên. –

4

Ghi nhật ký trực tiếp qua System.out.print/println được coi là thực hành kém.

Tại sao?

  1. Không an toàn 'chủ đề'. Đăng nhập từ nhiều chuỗi kết quả trong văn bản bị cắt xén
  2. Nó không linh hoạt vì nó được mã hóa cứng và không được định cấu hình.
  3. Không linh hoạt vì bạn không thể chỉ định mức độ chi tiết bạn muốn xem trong nhật ký (ví dụ:theo dõi chi tiết/logic gỡ lỗi cụ thể/cảnh báo ứng dụng/lỗi ứng dụng/lỗi ứng dụng gây tử vong). Bạn luôn nhận được rất nhiều và cần phải bình luận nhiều dòng mã để tránh quá tải đăng nhập.
  4. Nó không linh hoạt vì bạn không thể chỉ định gói/lớp bạn đang hoặc không quan tâm - một lần nữa bạn luôn nhận được rất nhiều và cần phải nhận xét nhiều dòng cho bất kỳ điều gì đơn giản hơn & cụ thể hơn
  5. Nó không linh hoạt bởi vì bạn không thể chuyển hướng nhật ký tới các bảng cơ sở dữ liệu & các cột, tệp, email, hệ thống tin nhắn, cảnh báo SMS, v.v.
  6. Nó không linh hoạt vì bạn không thể truyền các cấp độ đăng nhập khác nhau. Ngoài ra, bạn không thể cấu hình nó để đăng nhập vào cùng một điểm đến hoặc một đích khác nhau như máy chủ ứng dụng và nó JVM
  7. Đó là chậm khi bạn có hàng ngàn/triệu dòng được ghi vào đĩa vật lý

Năm 2000 , Log4J đã được giới thiệu.
Nó giải quyết tất cả những vấn đề này và đã trở thành giải pháp tiêu chuẩn hơn bao giờ hết. Mặc dù có một số công cụ ghi nhật ký lớn nhất & cố gắng vượt xa Log4J, nhưng bạn vẫn có thể nhận được kết quả mạnh mẽ, linh hoạt với Log4J. Nếu bạn chuyển tất cả các lệnh gọi System.out.print thành Log4J, thì vấn đề được trích dẫn của bạn và nhiều vấn đề khác sẽ biến mất.

http://logging.apache.org/log4j/1.2/manual.html

0

Để có kết quả trong thời trang không chồng chéo, sử dụng System.out.println. Sau đó u có thể chuyển hướng đến cùng một tập tin như thế này:

java -XX:+PrintCompilation -XX:+PrintGCDetails MainClass 1>stdout.txt 2>&1 

Đây là có tất cả các lỗi cũng như giao diện điều khiển đầu ra bình thường trong tên tập tin stdout.txt

Ngoài ra, nếu các bản ghi có bất kỳ hình thức chủ đề/thông tin thời gian, bạn có thể chỉ cần sử dụng

sort -n -k 1 

trong đó-k 1 đứng cho cột mà bạn có thông tin luồng/dữ liệu (epoch).

2

Đối với -XX:+PrintCompilation, bạn có thể sử dụng các cờ -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation để thay thế kết quả "tiết" trong tệp "hotspot.log" riêng biệt. Tệp này ở định dạng XML và chứa cả thông tin từ -XX:+PrintCompilation và nguyên nhân của các bộ sưu tập đó. Đường dẫn tệp có thể được thay đổi qua -XX:LogFile=<new_hotspot_log>. Tham chiếu: https://wikis.oracle.com/display/HotSpotInternals/LogCompilation+overview

Đối với -XX:+PrintGCDetails, bạn có thể sử dụng -Xloggc:<gc_log> để chuyển hướng đầu ra GC tới tệp được chỉ định. Tham khảo: java -X

Các vấn đề liên quan