Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic web analytics tracking implementation #681

Merged

Conversation

th3M1ke
Copy link
Contributor

@th3M1ke th3M1ke commented Jan 22, 2021

Which problem is this PR solving?

Short description of the changes

  • GA module was transferred to a separate class and will be invoked once UI configuration property UIConfig.tracking.gaID will be added
  • if will be provided customWebAnalytics implementation via UI configuration property UIConfig.tracking.customWebAnalytics it will be used as web analytic in jaeger UI
  • if any of UI configuration will not be provided - empty mock(() => {}) will be used
  • only one web analytic system can work. Priority: Custom Web Analytic -> Google Analytics -> Mock
  • UIConfig.tracking.customWebAnalytics format(also described in IWebAnalytics in types):
const CustomWebAnalytics: IWebAnalytics = {
    init: () => {},
    trackPageView: () => {},
    trackError: () => {},
    trackEvent: () => {},
    context: null,
    isEnabled: () => false,
};

UIconfig.js:

function UIConfig() {
  return {
     ...other properties
     tracking: {
       customWebAnalytics: function () {
         return {
           init: () => { /* initialization actions */ },
           trackPageView: (pathname, search) => {},
           trackError: (description) => {},
           trackEvent: (category, action, labelOrValue, value) => {},
           context: null,
           isEnabled: () => false,
         }
       }
     }
  }
}

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>
@codecov
Copy link

codecov bot commented Jan 22, 2021

Codecov Report

Merging #681 (491353a) into master (48956d5) will increase coverage by 0.12%.
The diff coverage is 93.25%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #681      +/-   ##
==========================================
+ Coverage   94.23%   94.36%   +0.12%     
==========================================
  Files         228      230       +2     
  Lines        5931     5959      +28     
  Branches     1492     1448      -44     
==========================================
+ Hits         5589     5623      +34     
+ Misses        304      302       -2     
+ Partials       38       34       -4     
Impacted Files Coverage Δ
...ackages/jaeger-ui/src/constants/default-config.tsx 100.00% <ø> (ø)
packages/jaeger-ui/src/middlewares/track.tsx 12.50% <0.00%> (-62.50%) ⬇️
packages/jaeger-ui/src/utils/tracking/utils.tsx 80.00% <80.00%> (ø)
packages/jaeger-ui/src/utils/tracking/ga.tsx 93.84% <93.84%> (ø)
packages/jaeger-ui/src/utils/tracking/index.tsx 100.00% <100.00%> (+20.83%) ⬆️
.../jaeger-ui/src/utils/tracking/noopWebAnalytics.tsx 100.00% <100.00%> (ø)
...kages/jaeger-ui/src/model/transform-trace-data.tsx 90.58% <0.00%> (ø)
.../jaeger-ui/src/components/common/BreakableText.tsx 83.33% <0.00%> (ø)
...ents/TracePage/TraceTimelineViewer/TimelineRow.tsx 77.77% <0.00%> (ø)
... and 4 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 48956d5...186e6c8. Read the comment docs.

Copy link
Member

@yurishkuro yurishkuro left a comment

Choose a reason for hiding this comment

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

it would be good to ramp up some test coverage, 0.19% drop is pretty big.

@@ -0,0 +1,30 @@
// Copyright (c) 2021 Uber Technologies, Inc.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Copyright (c) 2021 Uber Technologies, Inc.
// Copyright (c) 2021 The Jaeger Authors.

Copy link
Member

Choose a reason for hiding this comment

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

Is this header being added automatically?

Copy link
Contributor Author

@th3M1ke th3M1ke Jan 25, 2021

Choose a reason for hiding this comment

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

No, I believe I just copied it from some file...

@@ -0,0 +1,187 @@
// Copyright (c) 2021 Uber Technologies, Inc.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Copyright (c) 2021 Uber Technologies, Inc.
// Copyright (c) 2021 The Jaeger Authors.

}

export function trackError(description: string) {
if (isGaEnabled) {
let msg = description;
Copy link
Member

Choose a reason for hiding this comment

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

I'm confused - all this functionality now seems to only exist in the GA implementation of IWebAnalytics, but wasn't it a general functionality that would be applicable to any other implementation? I would've expected only the reporting part to be swapped out, not all the data preparation / massaging.


// Util so "0" and "false" become false
const isTruish = (value?: string | string[]) => Boolean(value) && value !== '0' && value !== 'false';
const GenericWebAnalytics: IWebAnalytics = {
Copy link
Member

Choose a reason for hiding this comment

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

maybe NoopWebAnalytics?

@@ -85,6 +85,7 @@ export default deepFreeze(
tracking: {
gaID: null,
trackErrors: true,
customWebAnalytics: null,
Copy link
Member

Choose a reason for hiding this comment

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

is there a place where the type of this function is defined (it seems to take config as arg)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I understand the question correct, my answer is yes it will look like

customWebAnalytics: function (config?) {
         return {
           init: () => { /* initialization actions */ },
           trackPageView: (pathname, search) => {},
           trackError: (description) => {},
           trackEvent: (category, action, labelOrValue, value) => {},
           context: null,
           isEnabled: () => false,
         }
       }

Copy link
Member

Choose a reason for hiding this comment

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

I meant whether we have a type definition for Config somewhere. Maybe not.

webAnalytics = config.tracking.customWebAnalytics(config) as IWebAnalytics;
} else if (config.tracking && config.tracking.gaID) {
webAnalytics = new GA(config);
}
Copy link
Member

Choose a reason for hiding this comment

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

Another option instead of forced priority order is to allow enabling both GA and custom WA via a wrapper implementation that would dispatch events to both. But I don't feel strongly about it, the priority order seems fine.

// enable for tests, debug or if in prod with a GA ID
export const isGaEnabled = isTest || isDebugMode || (isProd && Boolean(gaID));
const isErrorsEnabled = isDebugMode || (isGaEnabled && Boolean(_get(config, 'tracking.trackErrors')));
if (webAnalytics.isEnabled()) {
Copy link
Member

Choose a reason for hiding this comment

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

This feels like an odd ordering, checking a property before the object was initialized. I would call init() unconditionally. It can always check isEnabled internally if necessary, but perhaps in some cases init() would actually initialize that property (e.g by checking if a valid app token is provided in the constructor).

Copy link
Member

Choose a reason for hiding this comment

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

Alternatively, could this not be done directly in the constructor? No additional information is provided to init() anyway.

@th3M1ke
Copy link
Contributor Author

th3M1ke commented Jan 25, 2021

I'm confused - all this functionality now seems to only exist in the GA implementation of IWebAnalytics, but wasn't it a general functionality that would be applicable to any other implementation? I would've expected only the reporting part to be swapped out, not all the data preparation / massaging.

Do you suggest making a transport layer? if so, I do not clearly understand how should it look like. Currently, I lot of logic goes with GA and data preparation to be sent.

let's make alignment about the implementation itself:

  1. We have the next function that currently using:
  • trackPageView
  • trackError
  • trackEvent

trackPageView can be a part of trackEvent?
trackError - can be used for web analytics and, also we can pass the custom logger

Does this fit for you? Or can we reduce them to trackError and trackEvent?

  1. Once we add only the transport layer users can not modify incoming data and map it according to their needs
  2. Is invoking custom WA good from your perspective?
  return {
     ...other properties
     tracking: {
       customWebAnalytics: function () {
         return {
           init: () => { /* initialization actions */ },
           trackPageView: (pathname, search) => {},
           trackError: (description) => {},
           trackEvent: (category, action, labelOrValue, value) => {},
           context: null,
           isEnabled: () => false,
         }
       }
     }
  }
}

Another option instead of forced priority order is to allow enabling both GA and custom WA via a wrapper implementation that would dispatch events to both. But I don't feel strongly about it, the priority order seems fine.

Sure we can init them both in parallel. Wrappers could be implemented inside trackPageView, trackError, trackEvent in packages/jaeger-ui/src/utils/tracking/index.tsx

it would be good to ramp up some test coverage, 0.19% drop is pretty big.

Will add tests as we align about implementation if it is ok :)

@yurishkuro
Copy link
Member

Do you suggest making a transport layer?

Well, depends on how you look at it. Take the logic in the init method, for example - it determines app version, checks some cookies, configures raven, etc. A good 80-90 lines of code, of which maybe 5 are related to GA. So shouldn't that same functionality be available if you're reporting events to another provider?

@th3M1ke th3M1ke force-pushed the Generic-analytics-tracking-impl branch from 5b22d04 to 605f980 Compare February 1, 2021 23:57
Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>
@th3M1ke th3M1ke force-pushed the Generic-analytics-tracking-impl branch from 62f6f6a to 3f71ca3 Compare February 11, 2021 19:25
@th3M1ke
Copy link
Contributor Author

th3M1ke commented Feb 11, 2021

@yurishkuro, I'm not sure about transport. From my perspective transport layers remove flexibility, and add complexity. We need to expose adapters for different analytic systems or provide such ability to users.

About errors. Not all systems provide specific error tracking function. So you have to track them as events. But for errors user can provide a custom logger via configuration.

As for raven, we can provide it as a configuration and the user can decide to use it or not.

@yurishkuro
Copy link
Member

ok. We can refactor that later, right now it's not worse than it was before, so I'd be ok to merge.

@th3M1ke
Copy link
Contributor Author

th3M1ke commented Feb 11, 2021

🤝 Let me increase test coverage shortly!

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>
@th3M1ke
Copy link
Contributor Author

th3M1ke commented Feb 15, 2021

@yurishkuro can you take a look at codecov analysis? https://codecov.io/gh/jaegertracing/jaeger-ui/pull/681/diff

There are gaps under google analytics implementation. Those lines are related to development. Should I also cover them as well?

@yurishkuro
Copy link
Member

the rule of thumb is to leave the code with the cumulative coverage no worse than before

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>
@yurishkuro
Copy link
Member

seems the checks are stuck

@yurishkuro yurishkuro closed this Feb 15, 2021
@yurishkuro yurishkuro reopened this Feb 15, 2021
@yurishkuro
Copy link
Member

https://codecov.io/github/jaegertracing/jaeger-ui/commit/aa603193a1ed5daf343ce4d44ceda2d721ded953

Is it possible to run GA tests in both debug and non-debug mode? This will improve the coverage

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>
Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>
@yurishkuro
Copy link
Member

@yurishkuro yurishkuro merged commit abdf99d into jaegertracing:master Feb 16, 2021
vvvprabhakar pushed a commit to vvvprabhakar/jaeger-ui that referenced this pull request Jul 4, 2021
* Generic web analytics tracking implementation

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Update due to comments, refactor Google Analytic tracker

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Add unit tests

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Update tests

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Update tests

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Increase test coverage

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>
Signed-off-by: vvvprabhakar <vvvprabhakar@gmail.com>
vvvprabhakar pushed a commit to vvvprabhakar/jaeger-ui that referenced this pull request Jul 4, 2021
* Generic web analytics tracking implementation

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Update due to comments, refactor Google Analytic tracker

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Add unit tests

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Update tests

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Update tests

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Increase test coverage

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>
Signed-off-by: vvvprabhakar <vvvprabhakar@gmail.com>
vvvprabhakar pushed a commit to vvvprabhakar/jaeger-ui that referenced this pull request Jul 5, 2021
* Generic web analytics tracking implementation

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Update due to comments, refactor Google Analytic tracker

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Add unit tests

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Update tests

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Update tests

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>

* Increase test coverage

Signed-off-by: Mykhailo Semenchenko <mykhailo.semenchenko@logz.io>
Signed-off-by: vvvprabhakar <vvvprabhakar@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

generic analytics tracking (in addition to GA)
2 participants