AppLog.java 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package com.mes.util;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import java.io.PrintStream;
  5. import java.text.SimpleDateFormat;
  6. import java.util.Date;
  7. /** Lightweight local logging for the standalone MES desktop client. */
  8. public final class AppLog {
  9. private static final String APP_NAME = "mesclient-op060B-P02";
  10. private static final Object LOCK = new Object();
  11. private static final SimpleDateFormat TIME = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
  12. private static PrintStream out;
  13. private static volatile String exitReason;
  14. private static volatile String uncaughtThread;
  15. private static volatile Throwable uncaughtException;
  16. private AppLog() { }
  17. public static void init() {
  18. synchronized (LOCK) {
  19. if (out != null) return;
  20. try {
  21. File code = new File(AppLog.class.getProtectionDomain().getCodeSource().getLocation().toURI());
  22. File base = code.isFile() ? code.getParentFile() : new File(System.getProperty("user.dir"));
  23. File dir = new File(base, "logs");
  24. if (!dir.exists() && !dir.mkdirs()) return;
  25. String day = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
  26. out = new PrintStream(new FileOutputStream(new File(dir, APP_NAME + "-" + day + ".log"), true), true, "UTF-8");
  27. Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
  28. public void uncaughtException(Thread thread, Throwable exception) {
  29. exitReason = "UNCAUGHT_EXCEPTION";
  30. uncaughtThread = thread.getName();
  31. uncaughtException = exception;
  32. }
  33. });
  34. Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
  35. public void run() {
  36. if ("USER_CLOSE".equals(exitReason)) {
  37. log("INFO", "Client exited, reason=user-close", null);
  38. } else if ("UNCAUGHT_EXCEPTION".equals(exitReason)) {
  39. log("ERROR", "Client exited, reason=uncaught-exception, thread=" + clean(uncaughtThread), uncaughtException);
  40. }
  41. }
  42. }, APP_NAME + "-log-shutdown"));
  43. } catch (Exception ignored) {
  44. // Logging is best-effort and must not stop client startup.
  45. }
  46. }
  47. }
  48. public static void login(String userId, String method, boolean success) {
  49. log(success ? "INFO" : "WARN", "Login " + (success ? "succeeded" : "failed")
  50. + ", method=" + clean(method) + ", user=" + clean(userId), null);
  51. }
  52. public static void scan(String type, String code) {
  53. log("INFO", "Scan, type=" + clean(type) + ", code=" + clean(code), null);
  54. }
  55. public static void work(String action, String code, boolean success) {
  56. log(success ? "INFO" : "WARN", "Operation " + (success ? "succeeded" : "failed")
  57. + ", action=" + clean(action) + ", code=" + clean(code), null);
  58. }
  59. public static void markUserClose() {
  60. exitReason = "USER_CLOSE";
  61. }
  62. private static String clean(String value) {
  63. return value == null ? "" : value.replace('\r', ' ').replace('\n', ' ');
  64. }
  65. private static void log(String level, String message, Throwable exception) {
  66. synchronized (LOCK) {
  67. if (out == null) return;
  68. out.println("[" + TIME.format(new Date()) + "][" + level + "]["
  69. + Thread.currentThread().getName() + "] " + message);
  70. if (exception != null) exception.printStackTrace(out);
  71. out.flush();
  72. }
  73. }
  74. }