Created
December 27, 2019 02:05
-
-
Save aotian16/1fb9cd28d8ada0733b78271732cb22a0 to your computer and use it in GitHub Desktop.
android Logger custom log file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.os.Environment; | |
import android.os.Handler; | |
import android.os.HandlerThread; | |
import android.text.TextUtils; | |
import androidx.annotation.NonNull; | |
import androidx.annotation.Nullable; | |
import com.orhanobut.logger.DiskLogStrategy; | |
import com.orhanobut.logger.FormatStrategy; | |
import com.orhanobut.logger.LogStrategy; | |
import java.io.File; | |
import java.text.SimpleDateFormat; | |
import java.util.Date; | |
import java.util.Locale; | |
import static com.orhanobut.logger.Logger.ASSERT; | |
import static com.orhanobut.logger.Logger.DEBUG; | |
import static com.orhanobut.logger.Logger.ERROR; | |
import static com.orhanobut.logger.Logger.INFO; | |
import static com.orhanobut.logger.Logger.VERBOSE; | |
import static com.orhanobut.logger.Logger.WARN; | |
public class WxbCsvFormatStrategy implements FormatStrategy { | |
private static final String NEW_LINE = System.getProperty("line.separator"); | |
private static final String NEW_LINE_REPLACEMENT = " <br> "; | |
private static final String SEPARATOR = ","; | |
@NonNull | |
private final Date date; | |
@NonNull private final SimpleDateFormat dateFormat; | |
@NonNull private final LogStrategy logStrategy; | |
@Nullable | |
private final String tag; | |
private WxbCsvFormatStrategy(@NonNull WxbCsvFormatStrategy.Builder builder) { | |
date = builder.date; | |
dateFormat = builder.dateFormat; | |
logStrategy = builder.logStrategy; | |
tag = builder.tag; | |
} | |
@NonNull public static WxbCsvFormatStrategy.Builder newBuilder() { | |
return new WxbCsvFormatStrategy.Builder(); | |
} | |
@Override public void log(int priority, @Nullable String onceOnlyTag, @NonNull String message) { | |
String tag = formatTag(onceOnlyTag); | |
date.setTime(System.currentTimeMillis()); | |
StringBuilder builder = new StringBuilder(); | |
// machine-readable date/time | |
builder.append(Long.toString(date.getTime())); | |
// human-readable date/time | |
builder.append(SEPARATOR); | |
builder.append(dateFormat.format(date)); | |
// level | |
builder.append(SEPARATOR); | |
builder.append(logLevel(priority)); | |
// tag | |
builder.append(SEPARATOR); | |
builder.append(tag); | |
// message | |
if (message.contains(NEW_LINE)) { | |
// a new line would break the CSV format, so we replace it here | |
message = message.replaceAll(NEW_LINE, NEW_LINE_REPLACEMENT); | |
} | |
builder.append(SEPARATOR); | |
builder.append(message); | |
// new line | |
builder.append(NEW_LINE); | |
logStrategy.log(priority, tag, builder.toString()); | |
} | |
String logLevel(int value) { | |
switch (value) { | |
case VERBOSE: | |
return "VERBOSE"; | |
case DEBUG: | |
return "DEBUG"; | |
case INFO: | |
return "INFO"; | |
case WARN: | |
return "WARN"; | |
case ERROR: | |
return "ERROR"; | |
case ASSERT: | |
return "ASSERT"; | |
default: | |
return "UNKNOWN"; | |
} | |
} | |
@Nullable private String formatTag(@Nullable String tag) { | |
if (!TextUtils.isEmpty(tag) && !TextUtils.equals(this.tag, tag)) { | |
return this.tag + "-" + tag; | |
} | |
return this.tag; | |
} | |
public static final class Builder { | |
private static final int MAX_BYTES = 500 * 1024; // 500K averages to a 4000 lines per file | |
Date date; | |
SimpleDateFormat dateFormat; | |
LogStrategy logStrategy; | |
String tag = "PRETTY_LOGGER"; | |
private Builder() { | |
} | |
@NonNull public WxbCsvFormatStrategy.Builder date(@Nullable Date val) { | |
date = val; | |
return this; | |
} | |
@NonNull public WxbCsvFormatStrategy.Builder dateFormat(@Nullable SimpleDateFormat val) { | |
dateFormat = val; | |
return this; | |
} | |
@NonNull public WxbCsvFormatStrategy.Builder logStrategy(@Nullable LogStrategy val) { | |
logStrategy = val; | |
return this; | |
} | |
@NonNull public WxbCsvFormatStrategy.Builder tag(@Nullable String tag) { | |
this.tag = tag; | |
return this; | |
} | |
@NonNull public WxbCsvFormatStrategy build() { | |
if (date == null) { | |
date = new Date(); | |
} | |
if (dateFormat == null) { | |
dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss.SSS", Locale.UK); | |
} | |
if (logStrategy == null) { | |
String diskPath = Environment.getExternalStorageDirectory().getAbsolutePath(); | |
String folder = diskPath + File.separatorChar + "logger" + File.separatorChar + "wxb"; // custom folder here | |
HandlerThread ht = new HandlerThread("AndroidFileLogger." + folder); | |
ht.start(); | |
Handler handler = new WxbDiskLogStrategy.WriteHandler(ht.getLooper(), folder, MAX_BYTES); | |
logStrategy = new DiskLogStrategy(handler); | |
} | |
return new WxbCsvFormatStrategy(this); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.os.Handler; | |
import android.os.Looper; | |
import android.os.Message; | |
import androidx.annotation.NonNull; | |
import androidx.annotation.Nullable; | |
import com.orhanobut.logger.LogStrategy; | |
import java.io.File; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
public class WxbDiskLogStrategy implements LogStrategy { | |
@NonNull | |
private final Handler handler; | |
public WxbDiskLogStrategy(@NonNull Handler handler) { | |
this.handler = handler; | |
} | |
@Override public void log(int level, @Nullable String tag, @NonNull String message) { | |
// do nothing on the calling thread, simply pass the tag/msg to the background thread | |
handler.sendMessage(handler.obtainMessage(level, message)); | |
} | |
static class WriteHandler extends Handler { | |
@NonNull private final String folder; | |
private final int maxFileSize; | |
WriteHandler(@NonNull Looper looper, @NonNull String folder, int maxFileSize) { | |
super(looper); | |
this.folder = folder; | |
this.maxFileSize = maxFileSize; | |
} | |
@SuppressWarnings("checkstyle:emptyblock") | |
@Override public void handleMessage(@NonNull Message msg) { | |
String content = (String) msg.obj; | |
FileWriter fileWriter = null; | |
File logFile = getLogFile(folder, "logs"); | |
try { | |
fileWriter = new FileWriter(logFile, true); | |
writeLog(fileWriter, content); | |
fileWriter.flush(); | |
fileWriter.close(); | |
} catch (IOException e) { | |
if (fileWriter != null) { | |
try { | |
fileWriter.flush(); | |
fileWriter.close(); | |
} catch (IOException e1) { /* fail silently */ } | |
} | |
} | |
} | |
/** | |
* This is always called on a single background thread. | |
* Implementing classes must ONLY write to the fileWriter and nothing more. | |
* The abstract class takes care of everything else including close the stream and catching IOException | |
* | |
* @param fileWriter an instance of FileWriter already initialised to the correct file | |
*/ | |
private void writeLog(@NonNull FileWriter fileWriter, @NonNull String content) throws IOException { | |
fileWriter.append(content); | |
} | |
private File getLogFile(@NonNull String folderName, @NonNull String fileName) { | |
File folder = new File(folderName); | |
if (!folder.exists()) { | |
//TODO: What if folder is not created, what happens then? | |
folder.mkdirs(); | |
} | |
int newFileCount = 0; | |
File newFile; | |
File existingFile = null; | |
newFile = new File(folder, String.format("%s_%s.csv", fileName, newFileCount)); | |
while (newFile.exists()) { | |
existingFile = newFile; | |
newFileCount++; | |
newFile = new File(folder, String.format("%s_%s.csv", fileName, newFileCount)); | |
} | |
if (existingFile != null) { | |
if (existingFile.length() >= maxFileSize) { | |
return newFile; | |
} | |
return existingFile; | |
} | |
return newFile; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment