PlcLog.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. package com.bgy.autosale.utils;
  2. import android.content.Context;
  3. import android.os.Environment;
  4. import android.os.SystemClock;
  5. import android.text.TextUtils;
  6. import android.util.Log;
  7. import java.io.File;
  8. import java.io.FileDescriptor;
  9. import java.io.FileNotFoundException;
  10. import java.io.FileOutputStream;
  11. import java.io.IOException;
  12. import java.text.ParseException;
  13. import java.text.SimpleDateFormat;
  14. import java.util.ArrayList;
  15. import java.util.Date;
  16. import java.util.HashMap;
  17. import java.util.Locale;
  18. import java.util.TimeZone;
  19. import java.util.concurrent.TimeUnit;
  20. import io.reactivex.disposables.Disposable;
  21. import io.reactivex.schedulers.Schedulers;
  22. /**
  23. * Created by cjx on 2019/8/7
  24. * 说明:保存日志到本地文件
  25. */
  26. public class PlcLog {
  27. private static PlcLog plcLog;
  28. private boolean open = true;
  29. private final ClickHelper checkFileHelper = new ClickHelper(1000 * 60 * 30);//半小时允许检查一次
  30. private HashMap<String, String> logPaths;
  31. private String defaultFile = "";
  32. ArrayList<String> retFilePaths = new ArrayList<>();
  33. private Context appContext;
  34. private int count = 0;
  35. Disposable disposable;
  36. public static PlcLog getInstance() {
  37. if (plcLog == null) {
  38. synchronized (PlcLog.class) {
  39. if (plcLog == null) {
  40. plcLog = new PlcLog();
  41. }
  42. }
  43. }
  44. return plcLog;
  45. }
  46. public void initLogFile(Context context) {
  47. initLogFile(context, "", null, new Date());
  48. }
  49. public void initLogFile(Context context, String file) {
  50. initLogFile(context, file, null, new Date());
  51. }
  52. public void initLogFile(Context context, String file, String dir) {
  53. initLogFile(context, file, dir, new Date());
  54. }
  55. public void initLogFile(Context context, String file, String dir, Date newDate) {
  56. appContext = context.getApplicationContext();
  57. defaultFile = file;
  58. SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd", Locale.CHINA);
  59. String fileName = sdf.format(newDate) + file;
  60. String logFilePath;
  61. synchronized (PlcLog.class) {
  62. if (dir == null) {
  63. dir = getDiskCacheDir(context) + "/log/";
  64. } else {
  65. dir = dir + "/log/";
  66. }
  67. mkDir(dir);
  68. logFilePath = dir + fileName + ".txt";
  69. File logFile = new File(logFilePath);
  70. if (!logFile.exists()) {
  71. try {
  72. logFile.createNewFile();
  73. } catch (IOException e) {
  74. e.printStackTrace();
  75. }
  76. }
  77. logPaths.remove(file);
  78. logPaths.put(file, logFilePath);
  79. System.out.println("初始化日志 " + logFilePath);
  80. File logFileParent = logFile.getParentFile();
  81. retFilePaths.clear();
  82. if (logFileParent.listFiles()!=null) {
  83. for (File log : logFileParent.listFiles()) {
  84. String name = log.getName();
  85. if (name.length() > 2) {
  86. retFilePaths.add(log.getAbsolutePath());
  87. }
  88. }
  89. }
  90. }
  91. //考虑到网络时间没校准的时候
  92. checkAndDelLog(logFilePath);
  93. }
  94. private void checkAndDelLog(final String logFilePath) {
  95. if (disposable != null) {//销毁多余的延时
  96. disposable.dispose();
  97. disposable = null;
  98. }
  99. File logFile = (new File(logFilePath)).getParentFile();
  100. long current = System.currentTimeMillis();
  101. long checkTime = getEffectiveTime();
  102. //这么做是为了确保一下时间是准的网络时间
  103. if (current > checkTime) {
  104. if (logFile.listFiles()!=null) {
  105. for (File log : logFile.listFiles()) {
  106. String name = log.getName();
  107. if (name.startsWith("PLC_")) {
  108. try {
  109. if (current - log.lastModified() > 2592000000L) { // 30天前的日志, 要删除
  110. // if (current - log.lastModified() > 172800000) { // 2天前的日志, 要删除
  111. e("CJX", "删除 " + name + " = " + log.delete());
  112. }
  113. } catch (Exception e) {
  114. e.printStackTrace();
  115. }
  116. }
  117. }
  118. }
  119. } else {
  120. disposable = Schedulers.io().scheduleDirect(new Runnable() {
  121. @Override
  122. public void run() {
  123. checkAndDelLog(logFilePath);
  124. }
  125. }, 30, TimeUnit.SECONDS);
  126. }
  127. }
  128. public void setLogSwitch(boolean open) {
  129. this.open = open;
  130. }
  131. private PlcLog() {
  132. logPaths = new HashMap<>(2);
  133. }
  134. public String getLogFilePath() {
  135. return getLogFilePath("");
  136. }
  137. public String getLogFilePath(String file) {
  138. return logPaths.get(file);
  139. }
  140. private void internalSaveLog(String file, String tag, String msg) {
  141. if (!open) {
  142. return;
  143. }
  144. if (checkFileHelper.canClick() && appContext != null) {
  145. initLogFile(appContext);
  146. }
  147. String filePath = logPaths.get(file);
  148. if (TextUtils.isEmpty(filePath)) {
  149. filePath = logPaths.get(defaultFile);
  150. }
  151. if (!TextUtils.isEmpty(filePath)) {
  152. try {
  153. // 2021-09-26 15:05:39.714 6218-6251/
  154. FileOutputStream fileOutputStream = new FileOutputStream(filePath, true);
  155. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.CHINA);
  156. byte[] bytes = (sdf.format(new Date()) + " " + android.os.Process.myPid() + "-" + android.os.Process.myTid() + "/" + tag + ":" + msg + "\n").getBytes();
  157. fileOutputStream.write(bytes);
  158. fileOutputStream.flush();
  159. if (count++ > 8) {
  160. //将数据同步到达物理存储设备
  161. try {
  162. FileDescriptor fd = fileOutputStream.getFD();
  163. fd.sync();
  164. } catch (Exception e) {
  165. }
  166. count = 0;
  167. }
  168. fileOutputStream.close();
  169. } catch (FileNotFoundException e) {
  170. e.printStackTrace();
  171. } catch (IOException e) {
  172. e.printStackTrace();
  173. }
  174. }
  175. e(tag, msg);
  176. }
  177. public void ui(String tag, String msg) {
  178. ui("", tag, msg);
  179. }
  180. public void ui(String file, String tag, String msg) {
  181. e_s(file, tag, msg); //也要保持
  182. }
  183. /**
  184. * 打印日志并保存到文件,需要先调用{@link #initLogFile(Context)}初始化日志路径才生效
  185. *
  186. * @param tag 日志标签
  187. * @param msg 日志内容
  188. */
  189. public void e_s(String tag, String msg) {
  190. e_s("", tag, msg);
  191. }
  192. public void e_s(String file, String tag, String msg) {
  193. if (msg.length() > 4000) {
  194. for (int i = 0; i < msg.length(); i += 4000) {
  195. if (i + 4000 < msg.length())
  196. internalSaveLog(file, tag, msg.substring(i, i + 4000));
  197. else
  198. internalSaveLog(file, tag, msg.substring(i, msg.length()));
  199. }
  200. } else {
  201. //直接打印
  202. internalSaveLog(file, tag, msg);
  203. }
  204. }
  205. /**
  206. * 打印日志并保存到文件,需要先调用{@link #initLogFile(Context)}初始化日志路径才生效
  207. *
  208. * @param tag 日志标签
  209. * @param msg 日志内容
  210. */
  211. public void d_s(String tag, String msg) {
  212. d_s("", tag, msg);
  213. }
  214. public void d_s(String file, String tag, String msg) {
  215. //直接打印
  216. e_s(file, tag, msg);
  217. }
  218. public void e(String tag, String msg) {
  219. Log.e(tag, msg);
  220. }
  221. public void d(String tag, String msg) {
  222. if (!open) {
  223. return;
  224. }
  225. Log.d(tag, msg);
  226. }
  227. /**
  228. * 获取程序缓存路径
  229. */
  230. public static String getDiskCacheDir(Context context) {
  231. boolean hasExternal = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
  232. File cacheDir = hasExternal ? context.getExternalCacheDir() : context.getCacheDir();
  233. return cacheDir.getAbsolutePath();
  234. }
  235. /**
  236. * 创建当前目录的文件夹
  237. */
  238. private void mkDir(String filePath) {
  239. File file = new File(filePath);
  240. if (!file.exists()) {
  241. file.mkdirs();
  242. }
  243. }
  244. /**
  245. * 删除当前日志
  246. */
  247. public void delectLogFile() {
  248. delectLogFile("");
  249. }
  250. public void delectLogFile(String file) {
  251. String logFilePath = logPaths.get(file);
  252. if (logFilePath != null) {
  253. synchronized (PlcLog.class) {
  254. File f = new File(logFilePath);
  255. f.delete();
  256. }
  257. }
  258. }
  259. public String e_s(String tag, Exception ex) {
  260. try {
  261. StringBuilder stringBuilder = new StringBuilder();
  262. StackTraceElement[] stackTraceElements = ex.getStackTrace();
  263. for (StackTraceElement element : stackTraceElements) {
  264. stringBuilder.append("\n" + element.toString());
  265. }
  266. e_s(tag, stringBuilder.toString());
  267. return stringBuilder.toString();
  268. } catch (Exception e) {
  269. }
  270. return "";
  271. }
  272. public String e_s(String tag, Throwable ex) {
  273. try {
  274. StringBuilder stringBuilder = new StringBuilder();
  275. StackTraceElement[] stackTraceElements = ex.getStackTrace();
  276. for (StackTraceElement element : stackTraceElements) {
  277. stringBuilder.append("\n" + element.toString());
  278. }
  279. e_s(tag, stringBuilder.toString());
  280. return stringBuilder.toString();
  281. } catch (Exception e) {
  282. }
  283. return "";
  284. }
  285. public void printCallerStracks() {
  286. e_s("Stack", getCallers());
  287. }
  288. public static String getCallers() {
  289. final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
  290. StringBuilder stringBuilder = new StringBuilder();
  291. try {
  292. for (int i = 4; i < 10; i++) {
  293. stringBuilder.append("\n" + "class:" + callStack[i].getClassName() + " line:" + callStack[i].getLineNumber() + ":" + callStack[i].getMethodName());
  294. }
  295. } catch (Exception e) {
  296. }
  297. return stringBuilder.toString();
  298. }
  299. public static long getEffectiveTime() {
  300. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");// HH:mm:ss
  301. simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
  302. try {
  303. return simpleDateFormat.parse("2021-01-01").getTime();
  304. } catch (ParseException e) {
  305. e.printStackTrace();
  306. }
  307. return 0;
  308. }
  309. public ArrayList<String> getLogFilePaths() {
  310. return retFilePaths;
  311. }
  312. class ClickHelper {
  313. private long currentTime;
  314. private int timeOut;
  315. private volatile boolean lock = false;
  316. public ClickHelper(int timeOut) {
  317. this.timeOut = timeOut;
  318. }
  319. public boolean canClick() {
  320. if (lock) {
  321. currentTime = SystemClock.elapsedRealtime();
  322. //直接返回 false
  323. return false;
  324. }
  325. long time = SystemClock.elapsedRealtime();
  326. if ((time - currentTime) >= timeOut) {
  327. currentTime = time;
  328. return true;
  329. }
  330. return false;
  331. }
  332. public void setClickLock(boolean lock) {
  333. this.lock = lock;
  334. }
  335. }
  336. }