Initial cut of EventLogging support

This commit is contained in:
YuviPanda 2013-02-14 22:58:52 +05:30
parent 27ad2a6443
commit 5271cc57d1
7 changed files with 175 additions and 4 deletions

View file

@ -56,6 +56,10 @@ public class CommonsApplication extends Application {
private Account currentAccount = null; // Unlike a savings account...
public static final String API_URL = "https://test.wikipedia.org/w/api.php";
public static final String IMAGE_URL_BASE = "https://upload.wikimedia.org/wikipedia/test";
public static final String EVENTLOG_URL = "https://bits.wikimedia.org/event.gif";
public static final Object[] EVENT_UPLOAD_ATTEMPT = {"MobileAppUploadAttempts", 5241449};
public static final Object[] EVENT_LOGIN_ATTEMPT = {"MobileAppLoginAttempts", 5240393};
public static final String DEFAULT_EDIT_SUMMARY = "Uploaded using Android Commons app";

View file

@ -0,0 +1,99 @@
package org.wikimedia.commons;
import android.os.AsyncTask;
import de.akquinet.android.androlog.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class EventLog {
private static class LogTask extends AsyncTask<LogBuilder, Void, Boolean> {
@Override
protected Boolean doInBackground(LogBuilder... logBuilders) {
boolean allSuccess = true;
// Going to simply use the default URLConnection.
// This should be as lightweight as possible, and doesn't really do any fancy stuff
for(LogBuilder logBuilder: logBuilders) {
HttpURLConnection conn;
try {
URL url = logBuilder.toUrl();
conn = (HttpURLConnection) url.openConnection();
int respCode = conn.getResponseCode();
if(respCode != 204) {
allSuccess = false;
}
Log.d("Commons", "EventLog hit " + url.toString());
} catch (IOException e) {
// Probably just ignore for now. Can be much more robust with a service, etc later on.
// But in the interest of debugging
throw new RuntimeException(e);
}
}
return allSuccess;
}
}
public static class LogBuilder {
private JSONObject data;
private long rev;
private String schema;
private LogBuilder(String schema, long revision) {
data = new JSONObject();
this.schema = schema;
this.rev = revision;
}
public LogBuilder param(String key, Object value) {
try {
data.put(key, value);
} catch (JSONException e) {
throw new RuntimeException(e);
}
return this;
}
private URL toUrl() {
JSONObject fullData = new JSONObject();
try {
fullData.put("schema", schema);
fullData.put("revision", rev);
fullData.put("wiki", "commonswiki");
fullData.put("isValid", true); // Hehe
fullData.put("event", data);
return new URL(CommonsApplication.EVENTLOG_URL + "?" + Utils.urlEncode(fullData.toString()) + ";");
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
public void log() {
LogTask logTask = new LogTask();
Utils.executeAsyncTask(logTask, this);
}
}
public static LogBuilder schema(String schema, long revision) {
return new LogBuilder(schema, revision);
}
public static LogBuilder schema(Object[] schema_rev) {
if(schema_rev.length != 2) {
throw new IllegalArgumentException("Needs an object array with schema as first param and revision as second");
}
return schema((String)schema_rev[0], (Long)schema_rev[1]);
}
}

View file

@ -29,9 +29,19 @@ public class ShareActivity extends AuthenticatedActivity {
private Button uploadButton;
private EditText titleEdit;
private EditText descEdit;
private Uri mediaUri;
@Override
public void onBackPressed() {
super.onBackPressed();
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
.param("username", app.getCurrentAccount().name)
.param("source", getIntent().getStringExtra(UploadService.EXTRA_SOURCE))
.param("result", "cancelled")
.log();
}
@Override
protected void onAuthCookieAcquired(String authCookie) {
super.onAuthCookieAcquired(authCookie);
@ -42,6 +52,12 @@ public class ShareActivity extends AuthenticatedActivity {
if(intent.getAction().equals(Intent.ACTION_SEND)) {
mediaUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
final String source;
if(intent.hasExtra(UploadService.EXTRA_SOURCE)) {
source = intent.getStringExtra(UploadService.EXTRA_SOURCE);
} else {
source = Contribution.SOURCE_EXTERNAL;
}
final String mimeType = intent.getType();
if(mimeType.startsWith("image/")) {
@ -58,6 +74,7 @@ public class ShareActivity extends AuthenticatedActivity {
uploadIntent.putExtra(UploadService.EXTRA_DESCRIPTION, descEdit.getText().toString());
uploadIntent.putExtra(UploadService.EXTRA_MIMETYPE, mimeType);
uploadIntent.putExtra(UploadService.EXTRA_EDIT_SUMMARY, "Mobile upload from Wikimedia Commons Android app");
uploadIntent.putExtra(UploadService.EXTRA_SOURCE, source);
startService(uploadIntent);
Toast startingToast = Toast.makeText(that, R.string.uploading_started, Toast.LENGTH_LONG);
startingToast.show();

View file

@ -34,6 +34,7 @@ public class UploadService extends HandlerService<Contribution> {
public static final int ACTION_UPLOAD_FILE = 1;
public static final String ACTION_START_SERVICE = EXTRA_PREFIX + ".upload";
public static final String EXTRA_SOURCE = EXTRA_PREFIX + ".source";
private NotificationManager notificationManager;
private ContentProviderClient contributionsProviderClient;
@ -118,6 +119,7 @@ public class UploadService extends HandlerService<Contribution> {
String description = intent.getStringExtra(EXTRA_DESCRIPTION);
String editSummary = intent.getStringExtra(EXTRA_EDIT_SUMMARY);
String mimeType = intent.getStringExtra(EXTRA_MIMETYPE);
String source = intent.getStringExtra(EXTRA_SOURCE);
Date dateCreated = null;
Long length = null;
@ -144,6 +146,7 @@ public class UploadService extends HandlerService<Contribution> {
Removed Audio implementationf or now
} */
Contribution contribution = new Contribution(mediaUri, null, filename, description, length, dateCreated, null, app.getCurrentAccount().name, editSummary);
contribution.setSource(source);
return contribution;
}
@ -271,7 +274,14 @@ public class UploadService extends HandlerService<Contribution> {
String resultStatus = result.getString("/api/upload/@result");
if(!resultStatus.equals("Success")) {
String errorCode = result.getString("/api/error/@code");
showFailedNotification(contribution);
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
.param("username", app.getCurrentAccount().name)
.param("source", contribution.getSource())
.param("result", errorCode)
.param("filename", contribution.getFilename())
.log();
} else {
Date dateUploaded = null;
dateUploaded = Utils.parseMWDate(result.getString("/api/upload/imageinfo/@timestamp"));
@ -282,6 +292,13 @@ public class UploadService extends HandlerService<Contribution> {
contribution.setState(Contribution.STATE_COMPLETED);
contribution.setDateUploaded(dateUploaded);
contribution.save();
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
.param("username", app.getCurrentAccount().name)
.param("source", contribution.getSource()) //FIXME
.param("filename", contribution.getFilename())
.param("result", "success")
.log();
}
}

View file

@ -2,8 +2,10 @@ package org.wikimedia.commons;
import android.os.AsyncTask;
import android.os.Build;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.net.URLCodec;
import org.w3c.dom.Node;
import javax.xml.transform.TransformerConfigurationException;
@ -90,6 +92,16 @@ public class Utils {
}
}
private static final URLCodec urlCodec = new URLCodec();
public static String urlEncode(String url) {
try {
return urlCodec.encode(url);
} catch (EncoderException e) {
throw new RuntimeException(e);
}
}
public static long countBytes(InputStream stream) throws IOException {
long count = 0;
BufferedInputStream bis = new BufferedInputStream(stream);

View file

@ -11,6 +11,7 @@ import android.net.*;
import android.os.RemoteException;
import android.text.TextUtils;
import org.wikimedia.commons.CommonsApplication;
import org.wikimedia.commons.EventLog;
import org.wikimedia.commons.Media;
public class Contribution extends Media {
@ -21,8 +22,15 @@ public class Contribution extends Media {
public static final int STATE_QUEUED = 2;
public static final int STATE_IN_PROGRESS = 3;
public static final String SOURCE_CAMERA = "camera";
public static final String SOURCE_GALLERY = "gallery";
public static final String SOURCE_EXTERNAL = "external";
private ContentProviderClient client;
private Uri contentUri;
private String source;
public EventLog.LogBuilder event;
public long getTransferred() {
return transferred;
@ -132,6 +140,7 @@ public class Contribution extends Media {
cv.put(Table.COLUMN_TIMESTAMP, getTimestamp().getTime());
cv.put(Table.COLUMN_STATE, getState());
cv.put(Table.COLUMN_TRANSFERRED, transferred);
cv.put(Table.COLUMN_SOURCE, source);
return cv;
}
@ -159,9 +168,17 @@ public class Contribution extends Media {
c.dataLength = cursor.getLong(6);
c.dateUploaded = cursor.getLong(7) == 0 ? null : new Date(cursor.getLong(7));
c.transferred = cursor.getLong(8);
c.source = cursor.getString(9);
return c;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public static class Table {
@ -176,6 +193,7 @@ public class Contribution extends Media {
public static final String COLUMN_LENGTH = "length";
public static final String COLUMN_UPLOADED = "uploaded";
public static final String COLUMN_TRANSFERRED = "transferred"; // Currently transferred number of bytes
public static final String COLUMN_SOURCE = "source";
// NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES.
public static final String[] ALL_FIELDS = {
@ -187,7 +205,8 @@ public class Contribution extends Media {
COLUMN_STATE,
COLUMN_LENGTH,
COLUMN_UPLOADED,
COLUMN_TRANSFERRED
COLUMN_TRANSFERRED,
COLUMN_SOURCE
};
@ -200,7 +219,8 @@ public class Contribution extends Media {
+ "timestamp INTEGER,"
+ "state INTEGER,"
+ "length INTEGER,"
+ "transferred INTEGER"
+ "transferred INTEGER,"
+ "source STRING"
+ ");";

View file

@ -226,6 +226,7 @@ public class ContributionsActivity extends AuthenticatedActivity implements Load
Log.d("Commons", "Type is " + data.getType() + " Uri is " + data.getData());
shareIntent.setType("image/*"); //FIXME: Find out appropriate mime type
shareIntent.putExtra(Intent.EXTRA_STREAM, data.getData());
shareIntent.putExtra(UploadService.EXTRA_SOURCE, Contribution.SOURCE_GALLERY);
startActivity(shareIntent);
}
break;
@ -236,6 +237,7 @@ public class ContributionsActivity extends AuthenticatedActivity implements Load
Log.d("Commons", "Uri is " + lastGeneratedCaptureURI);
shareIntent.setType("image/jpeg"); //FIXME: Find out appropriate mime type
shareIntent.putExtra(Intent.EXTRA_STREAM, lastGeneratedCaptureURI);
shareIntent.putExtra(UploadService.EXTRA_SOURCE, Contribution.SOURCE_CAMERA);
startActivity(shareIntent);
}
break;