CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / toolkit / mozapps / extensions / AddonLogging.jsm
blob88bd71a6cf2dc9e21b3d43395769a245040f56f9
1 /*
2 # ***** BEGIN LICENSE BLOCK *****
3 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 # The contents of this file are subject to the Mozilla Public License Version
6 # 1.1 (the "License"); you may not use this file except in compliance with
7 # the License. You may obtain a copy of the License at
8 # http://www.mozilla.org/MPL/
10 # Software distributed under the License is distributed on an "AS IS" basis,
11 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 # for the specific language governing rights and limitations under the
13 # License.
15 # The Original Code is the Extension Manager.
17 # The Initial Developer of the Original Code is
18 # the Mozilla Foundation.
19 # Portions created by the Initial Developer are Copyright (C) 2010
20 # the Initial Developer. All Rights Reserved.
22 # Contributor(s):
23 #   Dave Townsend <dtownsend@oxymoronical.com>
25 # Alternatively, the contents of this file may be used under the terms of
26 # either the GNU General Public License Version 2 or later (the "GPL"), or
27 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 # in which case the provisions of the GPL or the LGPL are applicable instead
29 # of those above. If you wish to allow use of your version of this file only
30 # under the terms of either the GPL or the LGPL, and not to allow others to
31 # use your version of this file under the terms of the MPL, indicate your
32 # decision by deleting the provisions above and replace them with the notice
33 # and other provisions required by the GPL or the LGPL. If you do not delete
34 # the provisions above, a recipient may use your version of this file under
35 # the terms of any one of the MPL, the GPL or the LGPL.
37 # ***** END LICENSE BLOCK *****
40 const Cc = Components.classes;
41 const Ci = Components.interfaces;
42 const Cr = Components.results;
44 const KEY_PROFILEDIR                  = "ProfD";
45 const FILE_EXTENSIONS_LOG             = "extensions.log";
46 const PREF_LOGGING_ENABLED            = "extensions.logging.enabled";
48 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
50 Components.utils.import("resource://gre/modules/FileUtils.jsm");
51 Components.utils.import("resource://gre/modules/Services.jsm");
53 var EXPORTED_SYMBOLS = [ "LogManager" ];
55 var gDebugLogEnabled = false;
57 function formatLogMessage(aType, aName, aStr, aException) {
58   let message = aType.toUpperCase() + " " + aName + ": " + aStr;
59   if (aException)
60     return message + ": " + aException;
61   return message;
64 function getStackDetails(aException) {
65   // Defensively wrap all this to ensure that failing to get the message source
66   // doesn't stop the message from being logged
67   try {
68     if (aException) {
69       if (aException instanceof Ci.nsIException) {
70         return {
71           sourceName: aException.filename,
72           lineNumber: aException.lineNumber
73         };
74       }
76       return {
77         sourceName: aException.fileName,
78         lineNumber: aException.lineNumber
79       };
80     }
82     let stackFrame = Components.stack.caller.caller.caller;
83     return {
84       sourceName: stackFrame.filename,
85       lineNumber: stackFrame.lineNumber
86     };
87   }
88   catch (e) {
89     return {
90       sourceName: null,
91       lineNumber: 0
92     };
93   }
96 function AddonLogger(aName) {
97   this.name = aName;
100 AddonLogger.prototype = {
101   name: null,
103   error: function(aStr, aException) {
104     let message = formatLogMessage("error", this.name, aStr, aException);
106     let stack = getStackDetails(aException);
108     let consoleMessage = Cc["@mozilla.org/scripterror;1"].
109                          createInstance(Ci.nsIScriptError);
110     consoleMessage.init(message, stack.sourceName, null, stack.lineNumber, 0,
111                         Ci.nsIScriptError.errorFlag, "component javascript");
112     Services.console.logMessage(consoleMessage);
114     if (gDebugLogEnabled)
115       dump("*** " + message + "\n");
117     try {
118       var tstamp = new Date();
119       var logfile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_EXTENSIONS_LOG]);
120       var stream = Cc["@mozilla.org/network/file-output-stream;1"].
121                    createInstance(Ci.nsIFileOutputStream);
122       stream.init(logfile, 0x02 | 0x08 | 0x10, 0666, 0); // write, create, append
123       var writer = Cc["@mozilla.org/intl/converter-output-stream;1"].
124                    createInstance(Ci.nsIConverterOutputStream);
125       writer.init(stream, "UTF-8", 0, 0x0000);
126       writer.writeString(tstamp.toLocaleFormat("%Y-%m-%d %H:%M:%S ") +
127                          message + " at " + stack.sourceName + ":" +
128                          stack.lineNumber + "\n");
129       writer.close();
130     }
131     catch (e) { }
132   },
134   warn: function(aStr, aException) {
135     let message = formatLogMessage("warn", this.name, aStr, aException);
137     let stack = getStackDetails(aException);
139     let consoleMessage = Cc["@mozilla.org/scripterror;1"].
140                          createInstance(Ci.nsIScriptError);
141     consoleMessage.init(message, stack.sourceName, null, stack.lineNumber, 0,
142                         Ci.nsIScriptError.warningFlag, "component javascript");
143     Services.console.logMessage(consoleMessage);
145     if (gDebugLogEnabled)
146       dump("*** " + message + "\n");
147   },
149   log: function(aStr, aException) {
150     if (gDebugLogEnabled) {
151       let message = formatLogMessage("log", this.name, aStr, aException);
152       dump("*** " + message + "\n");
153       Services.console.logStringMessage(message);
154     }
155   }
158 var LogManager = {
159   getLogger: function(aName, aTarget) {
160     let logger = new AddonLogger(aName);
162     if (aTarget) {
163       ["error", "warn", "log"].forEach(function(name) {
164         let fname = name.toUpperCase();
165         delete aTarget[fname];
166         aTarget[fname] = function(aStr, aException) {
167           logger[name](aStr, aException);
168         };
169       });
170     }
172     return logger;
173   }
176 var PrefObserver = {
177   init: function() {
178     Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false);
179     Services.obs.addObserver(this, "xpcom-shutdown", false);
180     this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED);
181   },
183   observe: function(aSubject, aTopic, aData) {
184     if (aTopic == "xpcom-shutdown") {
185       Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this);
186       Services.obs.removeObserver(this, "xpcom-shutdown");
187     }
188     else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) {
189       try {
190         gDebugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED);
191       }
192       catch (e) {
193         gDebugLogEnabled = false;
194       }
195     }
196   }
199 PrefObserver.init();