Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 114 additions & 2 deletions segment.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ angular.module('ngSegment').constant('segmentDefaultConfig', {
// Debug: turns debug statements on/off. Useful during development.
debug: false,

// Allowed values:
// - string (in which case it will be interpreted as a name of a
// service debug messages will be emitted with, E.g. `$log`)
// - object
logger: '$log',

// Decides which method of the logger to use if debug is turned on.
debugLevel: 'log',

// Methods: the analytics.js methods that the service creates queueing stubs for.
methods: [
'trackSubmit',
Expand Down Expand Up @@ -187,7 +196,7 @@ angular.module('ngSegment').constant('segmentDefaultConfig', {
debug: function () {
if (this.config.debug) {
arguments[0] = this.config.tag + arguments[0];
console.log.apply(console, arguments);
this.logger[this.config.debugLevel].apply(this.logger, arguments);
return true;
}
},
Expand Down Expand Up @@ -237,6 +246,18 @@ angular.module('ngSegment').constant('segmentDefaultConfig', {
return this;
};

this.setLogger = function (logger) {
this.config.logger = logger;
this.validate('logger');
return this;
};

this.setDebugLevel = function (level) {
this.config.debugLevel = level;
this.validate('debugLevel');
return this;
};

this.setEvents = function (events) {
this.events = events;
return this;
Expand Down Expand Up @@ -289,6 +310,58 @@ angular.module('ngSegment').constant('segmentDefaultConfig', {
throw new Error(config.tag + 'Condition callback must be a function or array.');
}
},

logger: function (config) {
if (
!angular.isFunction(config.logger) &&
!angular.isObject(config.logger) &&
!angular.isString(config.logger) &&
(config.logger != null)
) {
throw new Error(config.tag + 'Logger must be either' +
' an object or a string or a function or' +
' undefined/null.');
}

var debugLevelType = typeof config.debugLevel;

if (angular.isObject(config.logger)) {
if (debugLevelType !== 'string') {
throw new Error(config.tag + 'Logger given' +
' as an object requires specifying' +
' `debugLevel` config as a string.' +
' `debugLevel` was a `' + debugLevelType + '`');
}
if (!(config.debugLevel in config.logger)) {
throw new Error(config.tag + 'Logger given' +
' as an object does not have a method called `' +
config.debugLevel + '` (set as' +
' `debugLevel`). Methods in the given' +
' object are: `' + Object
.keys(config.logger)
.filter(function (propName) {
return angular.isFunction(config.logger[propName])
})
.join(', ') + '`');
}
}

if (angular.isFunction(config.logger)) {
if (debugLevelType !== 'string') {
throw new Error(config.tag + 'Logger given' +
' as a function requires specifying' +
' `debugLevel` config as a string.' +
' `debugLevel` was a `' + debugLevelType + '`');
}
}
},

debugLevel: function (config) {
if (!angular.isString(config.debugLevel)) {
throw new Error(config.tag + '`debugLevel` must be' +
' a string.');
}
}
};

// Allows validating a specific property after set[Prop]
Expand All @@ -300,6 +373,12 @@ angular.module('ngSegment').constant('segmentDefaultConfig', {
};

this.createService = function ($injector, segmentLoader) {
var provider = this;

// Logger will be configured as soon as possible but `segmentConfig`
// may set up the logger because of that we need to gather messages
// logged before logger is set up.
var preLoggerDebugMessages = [];

// Apply user-provided config constant if it exists
if ($injector.has('segmentConfig')) {
Expand All @@ -309,7 +388,7 @@ angular.module('ngSegment').constant('segmentDefaultConfig', {
}

angular.extend(this.config, constant);
this.debug('Found segment config constant');
preLoggerDebugMessages.push('Found segment config constant');

// Validate settings passed in by constant
var _this = this;
Expand All @@ -318,6 +397,33 @@ angular.module('ngSegment').constant('segmentDefaultConfig', {
});
}

if ('logger' in this.config && this.config.logger) {
switch (typeof this.config.logger) {
case 'string':
if (!$injector.has(this.config.logger)) {
throw new Error(this.config.tag + 'Logger' +
' service `' + this.config.logger + '` is not' +
' known.');
}
this.logger = $injector.get(this.config.logger);
break;
case 'object':
this.logger = this.config.logger;
break;
case 'function':
this.logger = {};
this.logger[this.config.debugLevel] =
this.config.logger.bind(undefined);
break;
}
} else {
this.logger = $injector.get('$log');
}

preLoggerDebugMessages.forEach(function (message) {
provider.debug(message);
});

// Autoload Segment on service instantiation if an API key has been set via the provider
if (this.config.autoload) {
this.debug('Autoloading Analytics.js');
Expand Down Expand Up @@ -356,6 +462,12 @@ angular.module('ngSegment').constant('segmentDefaultConfig', {
segment[item.method].apply(segment, item.arguments);
});

// public debug has to be shadowed because it need to have
// access to the provider.
segment.debug = function () {
return Segment.prototype.debug.apply(provider, arguments);
};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aleross I had some problem with the prototype chain. For testing purposes (only?) segment service has debug function exposed. It did work but only if it wasn't referring properties declared only on the SegmentProvider (logger is only defined there). All internal uses of this.debug work as expected because dynamic context in all those cases is SegmentProvider. Calling segment.debug from outside made the context a segment service which has no logger (provider does).

I wanted not to expose the logger on segment (to prevent potential collisions with analytics.js api in the future) so I decided to shadow the method directly on the exposed object.

If you know of a better solution then please describe it. I'll be more than happy to learn something here :)


return segment;
};

Expand Down
2 changes: 1 addition & 1 deletion segment.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ angular.module('ngSegment').constant('segmentDefaultConfig', {
// Debug: turns debug statements on/off. Useful during development.
debug: false,

// Allowed values:
// - string (in which case it will be interpreted as a name of a
// service debug messages will be emitted with, E.g. `$log`)
// - object
logger: '$log',

// Decides which method of the logger to use if debug is turned on.
debugLevel: 'log',

// Methods: the analytics.js methods that the service creates queueing stubs for.
methods: [
'trackSubmit',
Expand Down
Loading