Skip to content

Commit e5ebb75

Browse files
committed
Merge pull request #257 from dronekit/improvement_write_log_to_file
Improvement write log to file
2 parents 593e646 + b3dc16e commit e5ebb75

File tree

8 files changed

+190
-14
lines changed

8 files changed

+190
-14
lines changed

ServiceApp/build.gradle

+13
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ def versionPatch = 4
4545
def versionBuild = 2 //bump for dogfood builds, public betas, etc.
4646
def versionPrefix = "3DR Services v"
4747

48+
//Log levels values
49+
def logLevelVerbose = 2;
50+
def logLevelDebug = 3;
51+
def logLevelInfo = 4;
52+
def logLevelWarn = 5;
53+
def logLevelError = 6;
54+
def logLevelAssert = 7;
55+
4856
android {
4957
compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)
5058
buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION
@@ -56,6 +64,10 @@ android {
5664

5765
versionCode computeVersionCode(versionMajor, versionMinor, versionPatch, versionBuild)
5866
versionName generateVersionName(versionPrefix, versionMajor, versionMinor, versionPatch)
67+
68+
//Write logs to file preferences
69+
buildConfigField "boolean", "WRITE_LOG_FILE", "false"
70+
buildConfigField "int", "LOG_FILE_LEVEL", "$logLevelDebug"
5971
}
6072

6173
compileOptions {
@@ -112,6 +124,7 @@ android {
112124
buildTypes {
113125
debug {
114126
versionNameSuffix generateVersionNameSuffix(versionBuild, "dev")
127+
buildConfigField "boolean", "WRITE_LOG_FILE", "true"
115128
}
116129

117130
beta {

ServiceApp/src/org/droidplanner/services/android/DroidPlannerServicesApp.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,27 @@
66
import io.fabric.sdk.android.Fabric;
77
import timber.log.Timber;
88

9+
import org.droidplanner.services.android.utils.LogToFileTree;
910
import org.droidplanner.services.android.utils.analytics.GAUtils;
1011
import org.droidplanner.services.android.utils.file.IO.ExceptionWriter;
1112

1213
public class DroidPlannerServicesApp extends Application {
1314

15+
private LogToFileTree logToFileTree;
16+
1417
@Override
1518
public void onCreate() {
1619
super.onCreate();
1720
Fabric.with(this, new Crashlytics());
1821

1922
if (BuildConfig.DEBUG) {
20-
Timber.plant(new Timber.DebugTree());
23+
if(BuildConfig.WRITE_LOG_FILE){
24+
logToFileTree = new LogToFileTree();
25+
Timber.plant(logToFileTree);
26+
}
27+
else {
28+
Timber.plant(new Timber.DebugTree());
29+
}
2130
}
2231

2332
final ExceptionWriter exceptionWriter = new ExceptionWriter(getApplicationContext());
@@ -36,4 +45,16 @@ public void uncaughtException(Thread thread, Throwable ex) {
3645
GAUtils.initGATracker(this);
3746
GAUtils.startNewSession(null);
3847
}
48+
49+
public void createFileStartLogging() {
50+
if (logToFileTree != null) {
51+
logToFileTree.createFileStartLogging(getApplicationContext());
52+
}
53+
}
54+
55+
public void closeLogFile() {
56+
if(logToFileTree != null) {
57+
logToFileTree.stopLoggingThread();
58+
}
59+
}
3960
}

ServiceApp/src/org/droidplanner/services/android/api/DroidPlannerService.java

+8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.o3dr.services.android.lib.model.IApiListener;
2222
import com.o3dr.services.android.lib.model.IDroidPlannerServices;
2323

24+
import org.droidplanner.services.android.DroidPlannerServicesApp;
2425
import org.droidplanner.services.android.core.MAVLink.connection.MavLinkConnection;
2526
import org.droidplanner.services.android.core.MAVLink.connection.MavLinkConnectionListener;
2627
import org.droidplanner.services.android.core.survey.CameraInfo;
@@ -361,6 +362,10 @@ public IBinder onBind(Intent intent) {
361362
@Override
362363
public void onCreate() {
363364
super.onCreate();
365+
366+
final DroidPlannerServicesApp dpApp = (DroidPlannerServicesApp) getApplication();
367+
dpApp.createFileStartLogging();
368+
364369
Timber.d("Creating 3DR Services.");
365370

366371
final Context context = getApplicationContext();
@@ -419,6 +424,9 @@ public void onDestroy() {
419424
dpServices.destroy();
420425

421426
stopForeground(true);
427+
428+
final DroidPlannerServicesApp dpApp = (DroidPlannerServicesApp) getApplication();
429+
dpApp.closeLogFile();
422430
}
423431

424432
@Override

ServiceApp/src/org/droidplanner/services/android/core/drone/DroneManager.java

-2
Original file line numberDiff line numberDiff line change
@@ -751,8 +751,6 @@ public void onDroneEvent(DroneInterfaces.DroneEventsType event, MavLinkDrone dro
751751
if (!soloComp.isConnected()) {
752752
soloComp.start();
753753
return;
754-
} else{
755-
soloComp.refreshState();
756754
}
757755
}
758756

ServiceApp/src/org/droidplanner/services/android/core/drone/companion/solo/controller/ControllerLinkManager.java

+3-6
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public void run() {
108108
if (version != null)
109109
controllerVersion.set(version);
110110

111+
updateControllerModeIfPossible();
111112
onVersionsUpdated();
112113
}
113114
};
@@ -346,7 +347,7 @@ public boolean isLinkConnected() {
346347
}
347348

348349
@Override
349-
public void refreshState(){
350+
public void refreshState() {
350351
Timber.d("Artoo link connected.");
351352

352353
startVideoManager();
@@ -358,15 +359,11 @@ public void refreshState(){
358359

359360
//Update the tx power compliance
360361
loadCurrentEUTxPowerComplianceMode();
361-
362-
updateControllerModeIfPossible();
363362
}
364363

365364
private void onVersionsUpdated(){
366365
if(linkListener != null && areVersionsSet())
367366
linkListener.onVersionsUpdated();
368-
369-
updateControllerModeIfPossible();
370367
}
371368

372369
private void updateControllerModeIfPossible() {
@@ -451,7 +448,7 @@ public void updateArtooMode(@SoloControllerMode.ControllerMode final int mode, f
451448
postAsyncTask(new Runnable() {
452449
@Override
453450
public void run() {
454-
Timber.d("Switching controller to mode %n", mode);
451+
Timber.d("Switching controller to mode %d", mode);
455452
try {
456453
final boolean supportControllerMode = doesSupportControllerMode();
457454
final String command = supportControllerMode
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package org.droidplanner.services.android.utils;
2+
3+
import android.content.Context;
4+
import android.content.pm.PackageInfo;
5+
import android.content.pm.PackageManager;
6+
import android.util.Log;
7+
8+
import org.droidplanner.services.android.BuildConfig;
9+
10+
import java.io.File;
11+
import java.io.FileOutputStream;
12+
import java.io.IOException;
13+
import java.io.PrintStream;
14+
import java.text.SimpleDateFormat;
15+
import java.util.Date;
16+
import java.util.Locale;
17+
import java.util.concurrent.LinkedBlockingQueue;
18+
import java.util.concurrent.atomic.AtomicBoolean;
19+
20+
import timber.log.Timber;
21+
22+
/**
23+
* Timber Tree to log specific log levels to a file
24+
*/
25+
public class LogToFileTree extends Timber.DebugTree {
26+
private static final SimpleDateFormat LOG_DATE_FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US);
27+
private static final SimpleDateFormat FILE_DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd_HH_mm", Locale.US);
28+
29+
private final LinkedBlockingQueue<String> logQueue = new LinkedBlockingQueue<>();
30+
private PrintStream logOutputFile;
31+
private Thread dequeueThread;
32+
private final AtomicBoolean isRunning = new AtomicBoolean(false);
33+
private final Date date = new Date();
34+
35+
@Override
36+
protected void log(int priority, String tag, String message, Throwable t) {
37+
super.log(priority, tag, message, t);
38+
39+
if (isLoggableToFile(priority)) {
40+
String logOutput = getLogMessage(priority, tag, message);
41+
logQueue.add(logOutput);
42+
}
43+
}
44+
45+
private boolean isLoggableToFile(int priority) {
46+
return priority >= BuildConfig.LOG_FILE_LEVEL;
47+
}
48+
49+
private String getLogMessage(int priority, String tag, String message) {
50+
String priorityShort = getPriorityString(priority);
51+
date.setTime(System.currentTimeMillis());
52+
return String.format("%s %s/%s : %s", LOG_DATE_FORMAT.format(date), priorityShort, tag, message);
53+
}
54+
55+
private String getPriorityString(int priority) {
56+
String priorityString = null;
57+
switch (priority) {
58+
case Log.ASSERT:
59+
priorityString = "ASSERT";
60+
break;
61+
case Log.ERROR:
62+
priorityString = "E";
63+
break;
64+
case Log.WARN:
65+
priorityString = "W";
66+
break;
67+
case Log.INFO:
68+
priorityString = "I";
69+
break;
70+
case Log.DEBUG:
71+
priorityString = "D";
72+
break;
73+
case Log.VERBOSE:
74+
priorityString = "V";
75+
break;
76+
default:
77+
priorityString = "";
78+
break;
79+
}
80+
return priorityString;
81+
}
82+
83+
public void createFileStartLogging(final Context context) {
84+
if (dequeueThread != null && dequeueThread.isAlive()) {
85+
stopLoggingThread();
86+
}
87+
88+
dequeueThread = new Thread(new Runnable() {
89+
public void run() {
90+
PackageInfo pInfo;
91+
String version = "";
92+
try {
93+
pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
94+
version = pInfo.versionName;
95+
} catch (PackageManager.NameNotFoundException e) {
96+
Timber.w("Failed to get package info");
97+
}
98+
99+
File rootDir = context.getExternalFilesDir(null);
100+
File dir = new File(rootDir, "/log_cat/");
101+
dir.mkdirs();
102+
103+
String fileName = String.format("%s_%s.log", version, FILE_DATE_FORMAT.format(new Date()));
104+
File logFile = new File(dir, fileName);
105+
try {
106+
logOutputFile = new PrintStream(new FileOutputStream(logFile, true));
107+
108+
while (isRunning.get()) {
109+
try {
110+
String message = logQueue.take();
111+
logOutputFile.println(message);
112+
} catch (InterruptedException e) {
113+
Timber.w("Failed to receive message from logQueue");
114+
}
115+
}
116+
117+
} catch (IOException e) {
118+
Timber.w("Failed to open file");
119+
} finally {
120+
isRunning.set(false);
121+
if (logOutputFile != null) {
122+
logOutputFile.close();
123+
}
124+
}
125+
}
126+
});
127+
128+
isRunning.set(true);
129+
dequeueThread.start();
130+
}
131+
132+
public void stopLoggingThread() {
133+
if (dequeueThread != null) {
134+
isRunning.set(false);
135+
dequeueThread.interrupt();
136+
dequeueThread = null;
137+
}
138+
}
139+
140+
}

ServiceApp/src/org/droidplanner/services/android/utils/file/DirectoryPath.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ public static String getCameraInfoPath(Context context) {
6161
/**
6262
* Storage folder for stacktraces
6363
*/
64-
public static String getLogCatPath(Context context) {
65-
return getPrivateDataPath(context) + "/log_cat/";
64+
public static String getCrashLogPath(Context context) {
65+
return getPrivateDataPath(context) + "/crash_log/";
6666
}
6767

6868
}

ServiceApp/src/org/droidplanner/services/android/utils/file/FileUtils.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.io.FileOutputStream;
88
import java.io.FilenameFilter;
99
import java.text.SimpleDateFormat;
10-
import java.util.Arrays;
1110
import java.util.Date;
1211
import java.util.Locale;
1312

@@ -57,11 +56,11 @@ static public File[] getFileList(String path, FilenameFilter filter) {
5756
}
5857

5958
public static FileOutputStream getExceptionFileStream(Context context) throws FileNotFoundException {
60-
File myDir = new File(DirectoryPath.getLogCatPath(context));
59+
File myDir = new File(DirectoryPath.getCrashLogPath(context));
6160
if (!myDir.exists())
6261
myDir.mkdirs();
6362

64-
File file = new File(myDir, getTimeStamp() + ".txt");
63+
File file = new File(myDir, getTimeStamp() + ".log");
6564
if (file.exists())
6665
file.delete();
6766
return new FileOutputStream(file);

0 commit comments

Comments
 (0)