Given an example stream config:
let CONFIG = { "edit": {}, "edit.growth.experiments.help_panel": {}, "edit.mobile.app": {}, "edit.mobile.web": {} };
a map of which streams should be cc'd (when any given stream is logged to) looks like
{ "edit": [ "edit.growth", "edit.mobile" ], "edit.growth": [ "edit.growth.experiments" ], "edit.growth.experiments": [ "edit.growth.experiments.help_panel" ], "edit.mobile": [ "edit.mobile.app", "edit.mobile.web" ] }
This map can be generated via the following:
/** * Generate a map for stream cc'ing. * * This enables us to determine which streams can be cc'd when logging an event * to a stream (e.g. edit ~> edit.growth). * * Stream cc-ing should be done only 1 level deep to avoid duplication. For * example, 'edit' shouldn't cc 'edits.growth' AND 'edits.growth.test', since * 'edits.growth' would, in turn, cc 'edits.growth.test'. * * Instead of working stream by stream to find children streams for each parent * stream, we work backwards by constructing parent streams from the children. * This enables children streams such as 'edits.growth.test' to be cc'd when * logging events to 'edits' even when parent streams 'edits' and/or * 'edits.growth' are not explicitly present in the stream configuration. */ mapCopyStreams = function( config ) { var cc_map = {}; // map of streams which are to be cc'd for (stream in config) { let s = stream.split( '.' ); let n_prefixes = s.length - 1; if ( n_prefixes > 1 ) { for (i = 1; i <= n_prefixes; i++) { var child = s.slice(0, i + 1).join( '.' ); var parent = s.slice(0, i).join ( '.' ); if ( !cc_map.hasOwnProperty( parent ) ) { Object.defineProperty( cc_map, parent, { value: [ child ], writable: true, enumerable: true }); } else { if (!cc_map[parent].includes( child ) ) { cc_map[parent].push( child ); } } } } else if ( n_prefixes === 1) { if ( !cc_map.hasOwnProperty( s[0] ) ) { Object.defineProperty( cc_map, s[0], { value: [ stream ], writable: true, enumerable: true }); } else { if ( !(cc_map[parent].includes( stream )) ) { cc_map[s[0]].push( stream ); } } } else { // no work to be done } } return cc_map; };
and can be verified by running
let COPIED = mapCopyStreams( CONFIG ); console.log( JSON.stringify(COPIED, null, 2) );
{ "edit": [ "edit.growth", "edit.mobile" ], "edit.growth": [ "edit.growth.experiments" ], "edit.growth.experiments": [ "edit.growth.experiments.help_panel" ], "edit.mobile": [ "edit.mobile.app", "edit.mobile.web" ] }
This is quite an expensive operation to perform at every pageload! It'd be great if, within EventLogging code, that map was simply just available and accessible the same way the stream config is.