Created
May 9, 2015 00:03
-
-
Save pyricau/06c2c486d24f5f85f7f0 to your computer and use it in GitHub Desktop.
Sending Leak Traces to a Slack Channel (and HipChat, see the comments)
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.util.Log; | |
import com.squareup.leakcanary.AnalysisResult; | |
import com.squareup.leakcanary.DisplayLeakService; | |
import com.squareup.leakcanary.HeapDump; | |
import retrofit.RestAdapter; | |
import retrofit.RetrofitError; | |
import retrofit.http.Multipart; | |
import retrofit.http.POST; | |
import retrofit.http.Part; | |
import retrofit.mime.TypedFile; | |
public final class LeakSlackUploadService extends DisplayLeakService { | |
/** See https://api.slack.com/ for documentation. */ | |
public interface SlackApi { | |
String TOKEN = "xoxp-SOME-USER-TOKEN"; | |
String MEMORY_LEAK_CHANNEL = "SOME-CHANNEL-TOKEN"; | |
@Multipart @POST("/api/files.upload") UploadFileResponse uploadFile(@Part("token") String token, | |
@Part("file") TypedFile file, @Part("filetype") String filetype, | |
@Part("filename") String filename, @Part("title") String title, | |
@Part("initial_comment") String initialComment, @Part("channels") String channels); | |
} | |
public static class UploadFileResponse { | |
boolean ok; | |
String error; | |
@Override public String toString() { | |
return "UploadFileResponse{" + | |
"ok=" + ok + | |
", error='" + error + '\'' + | |
'}'; | |
} | |
} | |
private static final String TAG = "LeakListenerService"; | |
private static String classSimpleName(String className) { | |
int separator = className.lastIndexOf('.'); | |
return separator == -1 ? className : className.substring(separator + 1); | |
} | |
private SlackApi slackApi; | |
@Override public void onCreate() { | |
super.onCreate(); | |
slackApi = new RestAdapter.Builder() // | |
.setEndpoint("https://slack.com") // | |
.build() // | |
.create(SlackApi.class); | |
} | |
@Override | |
protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) { | |
if (!result.leakFound || result.excludedLeak) { | |
return; | |
} | |
String name = classSimpleName(result.className); | |
if (!heapDump.referenceName.equals("")) { | |
name += "(" + heapDump.referenceName + ")"; | |
} | |
String title = name + " has leaked"; | |
String initialComment = leakInfo; | |
try { | |
slackApi.uploadFile(SlackApi.TOKEN, | |
new TypedFile("application/octet-stream", heapDump.heapDumpFile), null, | |
heapDump.heapDumpFile.getName(), title, initialComment, SlackApi.MEMORY_LEAK_CHANNEL); | |
} catch (RetrofitError e) { | |
Log.e(TAG, "Error when uploading heap dump", e); | |
} | |
} | |
} |
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
public class SquareDebugApplication extends SquareApplication { | |
@Override protected RefWatcher installLeakCanary() { | |
return LeakCanary.install(app, LeakSlackUploadService.class); | |
} | |
} |
Hey :)
After some digging here the snippet for uploading leaks using retrofit 2:
public final class LeakSlackUploadService extends DisplayLeakService
implements Callback<LeakSlackUploadService.UploadFileResponse> {
private SlackApi slackApi;
@Override
public void onCreate() {
super.onCreate();
slackApi = new Retrofit.Builder()
.baseUrl("https://slack.com")
.addConverterFactory(GsonConverterFactory.create())
.build() //
.create(SlackApi.class);
}
@Override
protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
Log.e(TAG, "afterDefaultHandling " + leakInfo);
if (!result.leakFound || result.excludedLeak) {
Log.e(TAG, "!result.leakFound || result.excludedLeak");
return;
}
String name = classSimpleName(result.className);
if (!heapDump.referenceName.equals("")) {
name += "(" + heapDump.referenceName + ")";
}
String title = name + " has leaked5";
String initialComment = leakInfo.substring(0, leakInfo.indexOf("Details:", 0));
RequestBody file = RequestBody
.create(MediaType.parse("multipart/form-data"), heapDump.heapDumpFile);
MultipartBody.Part body =
MultipartBody.Part.createFormData("file", heapDump.heapDumpFile.getName(), file);
final Call<UploadFileResponse> call = slackApi.uploadFile(SlackApi.TOKEN,
body,
null,
heapDump.heapDumpFile.getName(), title, initialComment,
SlackApi.MEMORY_LEAK_CHANNEL);
call.enqueue(this);
}
@Override
public void onResponse(Call<UploadFileResponse> call,
Response<UploadFileResponse> response) {
Log.d(TAG, response.body().toString());
}
@Override
public void onFailure(Call<UploadFileResponse> call, Throwable t) {
Log.d(TAG, t.getLocalizedMessage());
}
/** See https://api.slack.com/ for documentation. */
public interface SlackApi {
String TOKEN = "YOUR_TOKEN_SLACK";
String MEMORY_LEAK_CHANNEL = "YOUR_CHANNEL_FOR_MEMORY_LEAKS";
@Multipart
@POST("/api/files.upload")
Call<UploadFileResponse> uploadFile(
@Query("token") String token,
@Part MultipartBody.Part file, @Query("filetype") String filetype,
@Query("filename") String filename, @Query("title") String title,
@Query("initial_comment") String initialComment,
@Query("channels") String channels);
}
public static class UploadFileResponse {
boolean ok;
String error;
@Override
public String toString() {
return "UploadFileResponse{" +
"ok=" + ok +
", error='" + error + '\'' +
'}';
}
}
private static final String TAG = "LeakListenerService";
private static String classSimpleName(String className) {
int separator = className.lastIndexOf('.');
return separator == -1 ? className : className.substring(separator + 1);
}
}
(Solution below) Since LeakCanary 1.5, the install method mentioned above is no longer available.
Deprecated source (below)
public static RefWatcher androidWatcher(Context context, Listener heapDumpListener, ExcludedRefs excludedRefs) {
AndroidDebuggerControl debuggerControl = new AndroidDebuggerControl();
AndroidHeapDumper heapDumper = new AndroidHeapDumper(context);
heapDumper.cleanup();
return new RefWatcher(new AndroidWatchExecutor(), debuggerControl, GcTrigger.DEFAULT, heapDumper, heapDumpListener, excludedRefs);
}
Any ideas how to refactor the solution posted above to fit v1.5?
------------ Below is the solution -----------------
AndroidRefWatcherBuilder refWatcher = LeakCanary.refWatcher(this).listenerServiceClass(LeakSlackUploadService.class);
refWatcher.buildAndInstall();
When I do LeakCanary.refWatcher(this).listenerServiceClass(LeakSlackUploadService.class);
for builds with leakcanary-android-no-op, it throws no Static method exception.
LeakCanary.refWatcher(application)
.listenerServiceClass(LeakUploadService.class)
.buildAndInstall();
I wonder if anyone created code recipe to upload leak to slack for version 2.7 and Kotlin :) @pyricau
no. Slack bot means no aggregation so it's not as helpful as say Bugsnag.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Has anyone ever upload to flowdock or bug system (i.e. Asana, Jira)?