Bug 1121325 - improve sync logging with FxA. r=rnewman/ckarlof

This commit is contained in:
Mark Hammond 2015-01-23 12:05:14 +11:00
parent 23fc1eb071
commit 45231676f2
6 changed files with 51 additions and 28 deletions

View File

@ -37,24 +37,32 @@ Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
// loglevel should be one of "Fatal", "Error", "Warn", "Info", "Config", // log.appender.dump should be one of "Fatal", "Error", "Warn", "Info", "Config",
// "Debug", "Trace" or "All". If none is specified, "Error" will be used by // "Debug", "Trace" or "All". If none is specified, "Error" will be used by
// default. // default.
const PREF_LOG_LEVEL = "services.hawk.loglevel"; // Note however that Sync will also add this log to *its* DumpAppender, so
// in a Sync context it shouldn't be necessary to adjust this - however, that
// also means error logs are likely to be dump'd twice but that's OK.
const PREF_LOG_LEVEL = "services.common.hawk.log.appender.dump";
// A pref that can be set so "sensitive" information (eg, personally // A pref that can be set so "sensitive" information (eg, personally
// identifiable info, credentials, etc) will be logged. // identifiable info, credentials, etc) will be logged.
const PREF_LOG_SENSITIVE_DETAILS = "services.hawk.log.sensitive"; const PREF_LOG_SENSITIVE_DETAILS = "services.common.hawk.log.sensitive";
XPCOMUtils.defineLazyGetter(this, "log", function() { XPCOMUtils.defineLazyGetter(this, "log", function() {
let log = Log.repository.getLogger("Hawk"); let log = Log.repository.getLogger("Hawk");
log.addAppender(new Log.DumpAppender()); // We set the log itself to "debug" and set the level from the preference to
log.level = Log.Level.Error; // the appender. This allows other things to send the logs to different
// appenders, while still allowing the pref to control what is seen via dump()
log.level = Log.Level.Debug;
let appender = new Log.DumpAppender();
log.addAppender(appender);
appender.level = Log.Level.Error;
try { try {
let level = let level =
Services.prefs.getPrefType(PREF_LOG_LEVEL) == Ci.nsIPrefBranch.PREF_STRING Services.prefs.getPrefType(PREF_LOG_LEVEL) == Ci.nsIPrefBranch.PREF_STRING
&& Services.prefs.getCharPref(PREF_LOG_LEVEL); && Services.prefs.getCharPref(PREF_LOG_LEVEL);
log.level = Log.Level[level] || Log.Level.Error; appender.level = Log.Level[level] || Log.Level.Error;
} catch (e) { } catch (e) {
log.error(e); log.error(e);
} }
@ -99,12 +107,15 @@ this.HawkClient.prototype = {
* @param restResponse * @param restResponse
* A RESTResponse object from a RESTRequest * A RESTResponse object from a RESTRequest
* *
* @param errorString * @param error
* A string describing the error * A string or object describing the error
*/ */
_constructError: function(restResponse, errorString) { _constructError: function(restResponse, error) {
let errorObj = { let errorObj = {
error: errorString, // This object is likely to be JSON.stringify'd, but neither Error()
// objects nor Components.Exception objects do the right thing there,
// but .toString() works in both cases.
error: error.toString(),
message: restResponse.statusText, message: restResponse.statusText,
code: restResponse.status, code: restResponse.status,
errno: restResponse.status errno: restResponse.status
@ -190,6 +201,12 @@ this.HawkClient.prototype = {
let self = this; let self = this;
function _onComplete(error) { function _onComplete(error) {
// |error| can be either a normal caught error or an explicitly created
// Components.Exception() error. Log it now as it might not end up
// correctly in the logs by the time it's passed through _constructError.
if (error) {
log.warn("hawk request error", error);
}
let restResponse = this.response; let restResponse = this.response;
let status = restResponse.status; let status = restResponse.status;

View File

@ -458,6 +458,7 @@ RESTRequest.prototype = {
if (!statusSuccess) { if (!statusSuccess) {
let message = Components.Exception("", statusCode).name; let message = Components.Exception("", statusCode).name;
let error = Components.Exception(message, statusCode); let error = Components.Exception(message, statusCode);
this._log.debug(this.method + " " + uri + " failed: " + statusCode + " - " + message);
this.onComplete(error); this.onComplete(error);
this.onComplete = this.onProgress = null; this.onComplete = this.onProgress = null;
return; return;

View File

@ -9,4 +9,4 @@ pref("services.common.log.logger.rest.request", "Debug");
pref("services.common.log.logger.rest.response", "Debug"); pref("services.common.log.logger.rest.response", "Debug");
pref("services.common.storageservice.sendVersionInfo", true); pref("services.common.storageservice.sendVersionInfo", true);
pref("services.common.tokenserverclient.logger.level", "Info"); pref("services.common.log.logger.tokenserverclient", "Debug");

View File

@ -13,13 +13,13 @@ this.EXPORTED_SYMBOLS = [
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Preferences.jsm"); Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Log.jsm"); Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://services-common/rest.js"); Cu.import("resource://services-common/rest.js");
Cu.import("resource://services-common/utils.js"); Cu.import("resource://services-common/utils.js");
Cu.import("resource://services-common/observers.js"); Cu.import("resource://services-common/observers.js");
const Prefs = new Preferences("services.common.tokenserverclient."); const PREF_LOG_LEVEL = "services.common.log.logger.tokenserverclient";
/** /**
* Represents a TokenServerClient error that occurred on the client. * Represents a TokenServerClient error that occurred on the client.
@ -140,7 +140,7 @@ TokenServerClientServerError.prototype._toStringFields = function() {
*/ */
this.TokenServerClient = function TokenServerClient() { this.TokenServerClient = function TokenServerClient() {
this._log = Log.repository.getLogger("Common.TokenServerClient"); this._log = Log.repository.getLogger("Common.TokenServerClient");
this._log.level = Log.Level[Prefs.get("logger.level")]; this._log.level = Log.Level[Services.prefs.getCharPref(PREF_LOG_LEVEL)];
} }
TokenServerClient.prototype = { TokenServerClient.prototype = {
/** /**
@ -404,7 +404,7 @@ TokenServerClient.prototype = {
} }
} }
this._log.debug("Successful token response: " + result.id); this._log.debug("Successful token response");
cb(null, { cb(null, {
id: result.id, id: result.id,
key: result.key, key: result.key,

View File

@ -185,7 +185,7 @@ this.BrowserIDManager.prototype = {
// Reset the world before we do anything async. // Reset the world before we do anything async.
this.whenReadyToAuthenticate = Promise.defer(); this.whenReadyToAuthenticate = Promise.defer();
this.whenReadyToAuthenticate.promise.then(null, (err) => { this.whenReadyToAuthenticate.promise.then(null, (err) => {
this._log.error("Could not authenticate: " + err); this._log.error("Could not authenticate", err);
}); });
// initializeWithCurrentIdentity() can be called after the // initializeWithCurrentIdentity() can be called after the
@ -244,11 +244,11 @@ this.BrowserIDManager.prototype = {
this._shouldHaveSyncKeyBundle = true; // but we probably don't have one... this._shouldHaveSyncKeyBundle = true; // but we probably don't have one...
this.whenReadyToAuthenticate.reject(err); this.whenReadyToAuthenticate.reject(err);
// report what failed... // report what failed...
this._log.error("Background fetch for key bundle failed: " + err); this._log.error("Background fetch for key bundle failed", err);
}); });
// and we are done - the fetch continues on in the background... // and we are done - the fetch continues on in the background...
}).then(null, err => { }).then(null, err => {
this._log.error("Processing logged in account: " + err); this._log.error("Processing logged in account", err);
}); });
}, },
@ -531,14 +531,13 @@ this.BrowserIDManager.prototype = {
return null; return null;
} }
log.info("Fetching assertion and token from: " + tokenServerURI);
let maybeFetchKeys = () => { let maybeFetchKeys = () => {
// This is called at login time and every time we need a new token - in // This is called at login time and every time we need a new token - in
// the latter case we already have kA and kB, so optimise that case. // the latter case we already have kA and kB, so optimise that case.
if (userData.kA && userData.kB) { if (userData.kA && userData.kB) {
return; return;
} }
log.info("Fetching new keys");
return this._fxaService.getKeys().then( return this._fxaService.getKeys().then(
newUserData => { newUserData => {
userData = newUserData; userData = newUserData;
@ -565,7 +564,7 @@ this.BrowserIDManager.prototype = {
} }
let getAssertion = () => { let getAssertion = () => {
log.debug("Getting an assertion"); log.info("Getting an assertion from", tokenServerURI);
let audience = Services.io.newURI(tokenServerURI, null, null).prePath; let audience = Services.io.newURI(tokenServerURI, null, null).prePath;
return fxa.getAssertion(audience); return fxa.getAssertion(audience);
}; };
@ -602,13 +601,13 @@ this.BrowserIDManager.prototype = {
// properly: auth error getting assertion, auth error getting token (invalid generation // properly: auth error getting assertion, auth error getting token (invalid generation
// and client-state error) // and client-state error)
if (err instanceof AuthenticationError) { if (err instanceof AuthenticationError) {
this._log.error("Authentication error in _fetchTokenForUser: " + err); this._log.error("Authentication error in _fetchTokenForUser", err);
// set it to the "fatal" LOGIN_FAILED_LOGIN_REJECTED reason. // set it to the "fatal" LOGIN_FAILED_LOGIN_REJECTED reason.
this._authFailureReason = LOGIN_FAILED_LOGIN_REJECTED; this._authFailureReason = LOGIN_FAILED_LOGIN_REJECTED;
} else { } else {
this._log.error("Non-authentication error in _fetchTokenForUser: " this._log.error("Non-authentication error in _fetchTokenForUser", err);
+ (err.message || err)); // for now assume it is just a transient network related problem
// for now assume it is just a transient network related problem. // (although sadly, it might also be a regular unhandled exception)
this._authFailureReason = LOGIN_FAILED_NETWORK_ERROR; this._authFailureReason = LOGIN_FAILED_NETWORK_ERROR;
} }
// this._authFailureReason being set to be non-null in the above if clause // this._authFailureReason being set to be non-null in the above if clause
@ -657,7 +656,7 @@ this.BrowserIDManager.prototype = {
try { try {
cb.wait(); cb.wait();
} catch (ex) { } catch (ex) {
this._log.error("Failed to fetch a token for authentication: " + ex); this._log.error("Failed to fetch a token for authentication", ex);
return null; return null;
} }
if (!this._token) { if (!this._token) {
@ -742,6 +741,7 @@ BrowserIDClusterManager.prototype = {
cb(null, clusterURL); cb(null, clusterURL);
}).then( }).then(
null, err => { null, err => {
log.info("Failed to fetch the cluster URL", err);
// service.js's verifyLogin() method will attempt to fetch a cluster // service.js's verifyLogin() method will attempt to fetch a cluster
// URL when it sees a 401. If it gets null, it treats it as a "real" // URL when it sees a 401. If it gets null, it treats it as a "real"
// auth error and sets Status.login to LOGIN_FAILED_LOGIN_REJECTED, which // auth error and sets Status.login to LOGIN_FAILED_LOGIN_REJECTED, which

View File

@ -592,8 +592,13 @@ ErrorHandler.prototype = {
fapp.level = Log.Level[Svc.Prefs.get("log.appender.file.level")]; fapp.level = Log.Level[Svc.Prefs.get("log.appender.file.level")];
root.addAppender(fapp); root.addAppender(fapp);
// Arrange for the FxA logs to also go to our file. // Arrange for the FxA, Hawk and TokenServer logs to also go to our appenders.
Log.repository.getLogger("FirefoxAccounts").addAppender(fapp); for (let extra of ["FirefoxAccounts", "Hawk", "Common.TokenServerClient"]) {
let log = Log.repository.getLogger(extra);
for (let appender of [fapp, dapp, capp]) {
log.addAppender(appender);
}
}
}, },
observe: function observe(subject, topic, data) { observe: function observe(subject, topic, data) {