├── .gitignore
├── .project
├── .settings
└── com.salesforce.ide.core.prefs
├── README.md
├── salesforce.schema
└── src
├── applications
└── ApexLogger.app
├── classes
├── Logger.cls
├── Logger.cls-meta.xml
├── LoggerBackup.cls
├── LoggerBackup.cls-meta.xml
├── LoggerFactory.cls
├── LoggerFactory.cls-meta.xml
├── LoggerRecycleBin.cls
├── LoggerRecycleBin.cls-meta.xml
├── LoggerRecycleBinBatch.cls
├── LoggerRecycleBinBatch.cls-meta.xml
├── LoggerRecycleBinSchedule.cls
├── LoggerRecycleBinSchedule.cls-meta.xml
├── LoggerSettings.cls
├── LoggerSettings.cls-meta.xml
├── logger_TEST.cls
└── logger_TEST.cls-meta.xml
├── layouts
└── Log__c-Log Layout.layout
├── objects
├── Log__c.object
└── LoggerSettings__c.object
├── package.xml
├── remoteSiteSettings
└── Loggly.remoteSite
└── tabs
└── Log__c.tab
/.gitignore:
--------------------------------------------------------------------------------
1 | /salesforce.schema
2 | /Referenced Packages
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | apex-logger
4 |
5 |
6 |
7 |
8 |
9 | com.salesforce.ide.builder.online
10 |
11 |
12 |
13 |
14 | com.salesforce.ide.builder.default
15 |
16 |
17 |
18 |
19 |
20 | com.salesforce.ide.nature.default
21 | com.salesforce.ide.nature.online
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.settings/com.salesforce.ide.core.prefs:
--------------------------------------------------------------------------------
1 | #Mon Aug 20 15:13:36 BST 2012
2 | eclipse.preferences.version=1
3 | endpointApiVersion=25.0
4 | endpointEnvironment=Production/Developer Edition
5 | endpointServer=www.salesforce.com
6 | httpsProtocol=true
7 | ideVersion=25.0
8 | keependpoint=false
9 | metadataFormatVersion=25.0
10 | namespacePrefix=logger
11 | packageName=apexlogger
12 | readTimeout=400
13 | username=andyjmahood@gmail.com.log
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | apex-logger
2 | ===========
3 |
4 | Apex Logger replaces system.debug with logging in force.com projects
--------------------------------------------------------------------------------
/salesforce.schema:
--------------------------------------------------------------------------------
1 | place holder
--------------------------------------------------------------------------------
/src/applications/ApexLogger.app:
--------------------------------------------------------------------------------
1 |
2 |
3 | Log__c
4 |
5 | Log__c
6 |
7 |
--------------------------------------------------------------------------------
/src/classes/Logger.cls:
--------------------------------------------------------------------------------
1 | global without sharing class Logger {
2 |
3 | private String logName;
4 | private String logBody;
5 |
6 | global Logger(string logName) {
7 | this.logName = logName + ' - ' + Userinfo.getUserName();
8 | this.logBody = '';
9 |
10 | log('********** ' + logName + ' **********');
11 | log('ORG: ' + Userinfo.getOrganizationName() + '[' + Userinfo.getOrganizationId() + ']');
12 | log('USER: ' + Userinfo.getUserName() + '[' + Userinfo.getUserId() + ']');
13 | }
14 |
15 | /*
16 | writes a line into the log with date stamp
17 | */
18 | global void log(String message) {
19 | system.debug(message);
20 | logBody = logBody + '\n' + system.now().format() + ': ' + message;
21 | }
22 |
23 | /*
24 | persists log to database, additional method will hang off this
25 | eg. send log to loggr/loggly
26 | */
27 | global void commitLog() {
28 | try {
29 | Log__c log = buildLog();
30 |
31 | insert log;
32 | logBody='';
33 | } catch (Exception e) {
34 | system.debug('Failed to commit logs: ' + e);
35 | }
36 | }
37 |
38 | global string getLogName() {
39 | return logName;
40 | }
41 |
42 | /*
43 | creates the Log__c object to be persisted in databasedotcom
44 | */
45 | private Log__c buildLog() {
46 | Log__c log = new Log__c();
47 | if (logBody.length() > 32000) {
48 | logBody = logBody.substring(0, 31999);
49 | }
50 | log.Body__c = logBody;
51 | log.Name = logName;
52 | return log;
53 | }
54 | }
--------------------------------------------------------------------------------
/src/classes/Logger.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 23.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/LoggerBackup.cls:
--------------------------------------------------------------------------------
1 | public without sharing class LoggerBackup {
2 |
3 | private class callOutException extends Exception{}
4 | public boolean ENABLED;
5 | public string ENDPOINT;
6 |
7 | public LoggerBackup(){
8 | ENABLED = LoggerSettings.getBooleanValue('LOGGLY_ENABLED');
9 | ENDPOINT = LoggerSettings.getValue('LOGGLY_ENDPOINT');
10 |
11 | system.debug('LoggerBackup...ENABLED...' + ENABLED);
12 | system.debug('LoggerBackup...ENDPOINT...' + ENDPOINT);
13 | }
14 |
15 | public Boolean sendBackUp(String logBody) {
16 | if (!ENABLED) return true; //didnt happen but didnt need it backup anyway
17 |
18 | HttpRequest req = getHttpRequest(logBody);
19 | HttpResponse res = sendLog(req);
20 | return handleResponse(res);
21 | }
22 | private HttpRequest getHttpRequest(String logBody) {
23 | // Instantiate a new HTTP request, specify the method (GET) as well as the endpoint
24 | HttpRequest req = new HttpRequest();
25 | req.setEndpoint(ENDPOINT);
26 | req.setHeader('Content-Type', 'text/plain');
27 | req.setMethod('POST');
28 | req.setBody(logBody);
29 |
30 | return req;
31 | }
32 | private HttpResponse sendLog(HttpRequest req) {
33 | //Instantiate a new http object
34 | Http h = new Http();
35 | // Send the request, and return a response
36 | HttpResponse res = h.send(req);
37 |
38 | return res;
39 | }
40 | private Boolean handleResponse(HttpResponse res) {
41 |
42 | if (Test.isRunningTest() || res.getStatusCode()==200) {
43 | return true;
44 | } else {
45 | throw new callOutException('Error calling logging service: ' + res);
46 | return false;
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/classes/LoggerBackup.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 23.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/LoggerFactory.cls:
--------------------------------------------------------------------------------
1 | public with sharing class LoggerFactory {
2 | private static Map loggers = new Map();
3 |
4 | public static Logger getLogger() {
5 | return getLogger('Debug Log');
6 | }
7 | public static Logger getLogger(String name) {
8 | if (loggers.containsKey(name)) {
9 | return loggers.get(name);
10 | } else {
11 | System.debug('…\n…\n…\nCreating new logger for ' + name);
12 | Logger logger = new Logger(name);
13 | loggers.put(name, logger);
14 | return logger;
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/classes/LoggerFactory.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 23.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/LoggerRecycleBin.cls:
--------------------------------------------------------------------------------
1 | global with sharing class LoggerRecycleBin {
2 |
3 | global static String CRON_STR = '0 0 * * * ?';
4 |
5 | global static void purge() {
6 | recycleNow(-1);//will delete all created before tomorrow
7 | }
8 |
9 | global static void recycleNow() {
10 | integer purgeAfterDays = LoggerSettings.getIntegerValue('PURGE_AFTER_DAYS');
11 | if (purgeAfterDays==null) purgeAfterDays=7;//default to 7 days
12 | recycleNow(purgeAfterDays);
13 | }
14 |
15 | global static void recycleNow(integer dayToRecycle) {
16 | LoggerRecycleBinBatch recycleLogs = new LoggerRecycleBinBatch();
17 | recycleLogs.query = getLogQuery(dayToRecycle);
18 |
19 | // Invoke the batch job.
20 | ID batchprocessid = Database.executeBatch(recycleLogs, 1);
21 | System.debug('Returned batch process ID: ' + batchProcessId);
22 | }
23 |
24 | global static void schedule() {
25 |
26 | System.schedule('Logger Recycle Bin', CRON_STR, new LoggerRecycleBinSchedule());
27 | }
28 |
29 | public static string getLogQuery(integer dayToQuery) {
30 | Datetime d = Datetime.now();
31 | d = d.addDays(-dayToQuery);
32 |
33 | String query = 'SELECT Id, Body__c FROM Log__c WHERE CreatedDate < '+
34 | d.format('yyyy-MM-dd')+'T'+d.format('HH:mm')+':00.000Z';
35 |
36 | return query;
37 | }
38 | }
--------------------------------------------------------------------------------
/src/classes/LoggerRecycleBin.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 23.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/LoggerRecycleBinBatch.cls:
--------------------------------------------------------------------------------
1 | global class LoggerRecycleBinBatch implements Database.Batchable, Database.AllowsCallouts {
2 | public String query;
3 |
4 | global Database.QueryLocator start(Database.BatchableContext BC){
5 | if (query==null) query = LoggerRecycleBin.getLogQuery(-1);
6 | return Database.getQueryLocator(query);
7 | }
8 |
9 | global void execute(Database.BatchableContext BC, List scope){
10 | Log__c log = (Log__c)scope[0];
11 | Boolean safeToDelete=false;//can the delete be processed
12 |
13 | LoggerBackup logBackup = new LoggerBackup();
14 | safeToDelete = logBackup.sendBackUp(log.Body__c);
15 |
16 | /*
17 | safeToDelete means the backup was successful
18 | or loggly backup disabled
19 | */
20 | if (safeToDelete) {
21 | delete scope;
22 | DataBase.emptyRecycleBin(scope);
23 | }
24 | }
25 |
26 | global void finish(Database.BatchableContext BC){
27 |
28 | }
29 | }
--------------------------------------------------------------------------------
/src/classes/LoggerRecycleBinBatch.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 25.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/LoggerRecycleBinSchedule.cls:
--------------------------------------------------------------------------------
1 | global class LoggerRecycleBinSchedule implements Schedulable {
2 |
3 | global void execute(SchedulableContext ctx) {
4 | LoggerRecycleBin.recycleNow();
5 | }
6 | }
--------------------------------------------------------------------------------
/src/classes/LoggerRecycleBinSchedule.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 23.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/LoggerSettings.cls:
--------------------------------------------------------------------------------
1 | public with sharing class LoggerSettings {
2 |
3 | public static string getValue(string key) {
4 | system.debug('getting value for key...' + key);
5 |
6 | LoggerSettings__c settingValue = LoggerSettings__c.getInstance(key);
7 | if (settingValue!= null && settingValue.Value__c!=null && settingValue.Value__c!='') {
8 | system.debug('returning value for key...' + key + '...value...' + settingValue.Value__c);
9 | return settingValue.Value__c;
10 | } else {
11 | system.debug('returning value for key...' + key + '...value...[null]');
12 | return null;
13 | }
14 | }
15 | public static integer getIntegerValue(string key) {
16 | string retVal = getValue(key);
17 | return (retVal!=null) ? integer.valueOf(retVal) : null;
18 | }
19 | public static boolean getBooleanValue(string key) {
20 | string retVal = getValue(key);
21 | return (retVal!=null && retVal.equals('TRUE'));
22 | }
23 | }
--------------------------------------------------------------------------------
/src/classes/LoggerSettings.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 23.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/classes/logger_TEST.cls:
--------------------------------------------------------------------------------
1 | @isTest
2 | private class logger_TEST {
3 |
4 | static testMethod void testDefaultLogging() {
5 | Test.startTest();
6 |
7 | Logger defaultLog = LoggerFactory.getLogger();
8 | defaultLog.log('This is a default log ');
9 |
10 | //this will concatenate onto the default log
11 | Logger defaultLog2 = LoggerFactory.getLogger();
12 | defaultLog2.log('This is another on the default default log ');
13 |
14 | //both have same name
15 | system.assertEquals('Debug Log - ' + Userinfo.getUserName(), defaultLog.getLogName());
16 | system.assertEquals('Debug Log - ' + Userinfo.getUserName(), defaultLog2.getLogName());
17 |
18 | List logs = null;
19 | logs = [SELECT ID FROM Log__c];
20 | system.assertEquals(0,logs.size());//no logs committed yet
21 |
22 | defaultLog2.commitLog();
23 |
24 | logs = [SELECT ID FROM Log__c];
25 | system.assertEquals(1,logs.size());//one log committed
26 |
27 | LoggerRecycleBin.purge();//purge all logs
28 |
29 | Test.stopTest();
30 |
31 | }
32 |
33 | static testMethod void testCustomLogging() {
34 | Test.startTest();
35 |
36 | Logger log = LoggerFactory.getLogger('TESTLOG');
37 | log.log('This is a log ');
38 |
39 | system.assertEquals('TESTLOG - ' + Userinfo.getUserName(), log.getLogName());
40 |
41 | List logs = null;
42 | logs = [SELECT ID FROM Log__c];
43 | system.assertEquals(0,logs.size());//no logs committed yet
44 |
45 | log.commitLog();
46 |
47 | logs = [SELECT ID FROM Log__c];
48 | system.assertEquals(1,logs.size());//one log committed
49 |
50 | LoggerRecycleBin.purge();//purge all logs
51 |
52 | Test.stopTest();
53 |
54 | logs = [SELECT ID FROM Log__c];
55 | system.assertEquals(0,logs.size());//no logs committed
56 |
57 |
58 | }
59 |
60 | static testmethod void scheudleTest() {
61 | Test.startTest();
62 |
63 | // Schedule the test job
64 | String jobId = System.schedule('LoggerRecycleBinSchedule', LoggerRecycleBin.CRON_STR,
65 | new LoggerRecycleBinSchedule());
66 |
67 | CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered,
68 | NextFireTime
69 | FROM CronTrigger WHERE id = :jobId];
70 |
71 | //Verify the expressions are the same
72 | System.assertEquals(LoggerRecycleBin.CRON_STR, ct.CronExpression);
73 |
74 | // Verify the job has not run
75 | System.assertEquals(0, ct.TimesTriggered);
76 |
77 | Test.stopTest();
78 |
79 | }
80 |
81 |
82 | static testmethod void loggerBackupTest() {
83 | LoggerBackup backup = new LoggerBackup();
84 | backup.ENABLED = true;
85 | backup.ENDPOINT = '/xxx/';
86 |
87 | system.assertEquals(true, backup.sendBackUp('to log'));
88 | }
89 | }
--------------------------------------------------------------------------------
/src/classes/logger_TEST.cls-meta.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 24.0
4 | Active
5 |
6 |
--------------------------------------------------------------------------------
/src/layouts/Log__c-Log Layout.layout:
--------------------------------------------------------------------------------
1 |
2 |
3 | Submit
4 |
5 | false
6 | false
7 | true
8 |
9 |
10 |
11 | Required
12 | Name
13 |
14 |
15 | Readonly
16 | CreatedById
17 |
18 |
19 |
20 |
21 | Edit
22 | OwnerId
23 |
24 |
25 | Readonly
26 | LastModifiedById
27 |
28 |
29 |
30 |
31 |
32 | true
33 | false
34 | false
35 |
36 |
37 |
38 | Edit
39 | Body__c
40 |
41 |
42 |
43 |
44 |
45 | false
46 | false
47 | true
48 |
49 |
50 |
51 |
52 |
53 |
54 | true
55 | false
56 | true
57 |
58 |
59 |
60 |
61 |
62 |
63 | false
64 | true
65 | true
66 | false
67 | false
68 |
69 | 00hd000000M94xw
70 | 4
71 | 0
72 | Default
73 |
74 |
75 |
--------------------------------------------------------------------------------
/src/objects/Log__c.object:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Accept
5 | Default
6 |
7 |
8 | Clone
9 | Default
10 |
11 |
12 | Delete
13 | Default
14 |
15 |
16 | Edit
17 | Default
18 |
19 |
20 | List
21 | Default
22 |
23 |
24 | New
25 | Default
26 |
27 |
28 | Tab
29 | Default
30 |
31 |
32 | View
33 | Default
34 |
35 | Deployed
36 | Developer logs of debug events
37 | false
38 | false
39 | false
40 | true
41 |
42 | Body__c
43 | false
44 |
45 | 32000
46 | LongTextArea
47 | 5
48 |
49 |
50 |
51 | All
52 | NAME
53 | CREATEDBY_USER
54 | Everything
55 |
56 |
57 |
58 |
59 | Text
60 |
61 | Logs
62 |
63 | ReadWrite
64 |
65 |
--------------------------------------------------------------------------------
/src/objects/LoggerSettings__c.object:
--------------------------------------------------------------------------------
1 |
2 |
3 | List
4 | Public
5 | false
6 |
7 | Value__c
8 | false
9 |
10 | 255
11 | true
12 | Text
13 | false
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | apexlogger
4 | Unrestricted
5 | logger
6 | 25.0
7 |
8 |
--------------------------------------------------------------------------------
/src/remoteSiteSettings/Loggly.remoteSite:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 | true
5 | https://logs.loggly.com
6 |
7 |
--------------------------------------------------------------------------------
/src/tabs/Log__c.tab:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | false
5 | Custom57: Building Block
6 |
7 |
--------------------------------------------------------------------------------