diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index 5edcfa163d..eedcaa182b 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -409,6 +409,7 @@ export interface IN8nUISettings { telemetry: ITelemetrySettings; personalizationSurvey: IPersonalizationSurvey; defaultLocale: string; + logLevel: 'info' | 'debug' | 'warn' | 'error' | 'verbose'; } export interface IPersonalizationSurveyAnswers { diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 9ecf248057..3eb9e17a53 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -288,6 +288,7 @@ class App { shouldShow: false, }, defaultLocale: config.get('defaultLocale'), + logLevel: config.get('logs.level'), }; } diff --git a/packages/editor-ui/src/App.vue b/packages/editor-ui/src/App.vue index 1fba7209f0..c248d1f626 100644 --- a/packages/editor-ui/src/App.vue +++ b/packages/editor-ui/src/App.vue @@ -22,6 +22,9 @@ export default Vue.extend({ components: { Telemetry, }, + mounted() { + this.$telemetry.page('Editor', this.$route.name); + }, watch: { '$route'(route) { this.$telemetry.page('Editor', route.name); diff --git a/packages/editor-ui/src/Interface.ts b/packages/editor-ui/src/Interface.ts index 57ed602bf6..3c406dc1e2 100644 --- a/packages/editor-ui/src/Interface.ts +++ b/packages/editor-ui/src/Interface.ts @@ -536,6 +536,7 @@ export interface IN8nUISettings { personalizationSurvey?: IPersonalizationSurvey; telemetry: ITelemetrySettings; defaultLocale: string; + logLevel: ILogLevel; } export interface IWorkflowSettings extends IWorkflowSettingsWorkflow { @@ -680,7 +681,6 @@ export interface IRootState { workflow: IWorkflowDb; sidebarMenuItems: IMenuItem[]; instanceId: string; - telemetry: ITelemetrySettings | null; } export interface ICredentialTypeMap { @@ -718,6 +718,8 @@ export interface IUiState { isPageLoading: boolean; } +export type ILogLevel = 'info' | 'debug' | 'warn' | 'error' | 'verbose'; + export interface ISettingsState { settings: IN8nUISettings; promptsData: IN8nPrompts; diff --git a/packages/editor-ui/src/components/Telemetry.vue b/packages/editor-ui/src/components/Telemetry.vue index 7f3c72d82d..ac7978b513 100644 --- a/packages/editor-ui/src/components/Telemetry.vue +++ b/packages/editor-ui/src/components/Telemetry.vue @@ -10,12 +10,12 @@ import { mapGetters } from 'vuex'; export default Vue.extend({ name: 'Telemetry', computed: { - ...mapGetters(['telemetry']), + ...mapGetters('settings', ['telemetry']), }, watch: { telemetry(opts) { - if (opts.enabled) { - this.$telemetry.init(opts, this.$store.getters.instanceId); + if (opts && opts.enabled) { + this.$telemetry.init(opts, this.$store.getters.instanceId, this.$store.getters['settings/logLevel']); } }, }, diff --git a/packages/editor-ui/src/modules/settings.ts b/packages/editor-ui/src/modules/settings.ts index aba38ee7ae..3332f2cc92 100644 --- a/packages/editor-ui/src/modules/settings.ts +++ b/packages/editor-ui/src/modules/settings.ts @@ -1,5 +1,6 @@ import { ActionContext, Module } from 'vuex'; import { + ILogLevel, IN8nPrompts, IN8nUISettings, IN8nValueSurveyData, @@ -11,6 +12,7 @@ import { getPromptsData, getSettings, submitValueSurvey, submitPersonalizationSu import Vue from 'vue'; import { getPersonalizedNodeTypes } from './helper'; import { CONTACT_PROMPT_MODAL_KEY, PERSONALIZATION_MODAL_KEY, VALUE_SURVEY_MODAL_KEY } from '@/constants'; +import { ITelemetrySettings } from 'n8n-workflow'; const module: Module = { namespaced: true, @@ -30,6 +32,15 @@ const module: Module = { getPromptsData(state: ISettingsState) { return state.promptsData; }, + telemetry: (state): ITelemetrySettings => { + return state.settings.telemetry; + }, + logLevel: (state): ILogLevel => { + return state.settings.logLevel; + }, + isTelemetryEnabled: (state) => { + return state.settings.telemetry && state.settings.telemetry.enabled; + }, }, mutations: { setSettings(state: ISettingsState, settings: IN8nUISettings) { @@ -66,7 +77,6 @@ const module: Module = { context.commit('setN8nMetadata', settings.n8nMetadata || {}, {root: true}); context.commit('setDefaultLocale', settings.defaultLocale, {root: true}); context.commit('versions/setVersionNotificationSettings', settings.versionNotifications, {root: true}); - context.commit('setTelemetry', settings.telemetry, {root: true}); const showPersonalizationsModal = settings.personalizationSurvey && settings.personalizationSurvey.shouldShow && !settings.personalizationSurvey.answers; @@ -81,7 +91,7 @@ const module: Module = { context.commit('setPersonalizationAnswers', results); }, async fetchPromptsData(context: ActionContext) { - if (!context.rootGetters.isTelemetryEnabled) { + if (!context.getters.isTelemetryEnabled) { return; } diff --git a/packages/editor-ui/src/plugins/telemetry/index.ts b/packages/editor-ui/src/plugins/telemetry/index.ts index 8b6bc3d180..146d4d1f48 100644 --- a/packages/editor-ui/src/plugins/telemetry/index.ts +++ b/packages/editor-ui/src/plugins/telemetry/index.ts @@ -3,7 +3,7 @@ import { ITelemetrySettings, IDataObject, } from 'n8n-workflow'; -import { INodeCreateElement } from "@/Interface"; +import { ILogLevel, INodeCreateElement } from "@/Interface"; declare module 'vue/types/vue' { interface Vue { @@ -35,6 +35,8 @@ interface IUserNodesPanelSession { class Telemetry { + private pageEventQueue: Array<{category?: string, name?: string | null}>; + private get telemetry() { // @ts-ignore return window.rudderanalytics; @@ -49,14 +51,20 @@ class Telemetry { }, }; - init(options: ITelemetrySettings, instanceId: string) { + constructor() { + this.pageEventQueue = []; + } + + init(options: ITelemetrySettings, instanceId: string, logLevel?: ILogLevel) { if (options.enabled && !this.telemetry) { if(!options.config) { return; } - this.loadTelemetryLibrary(options.config.key, options.config.url, { integrations: { All: false }, loadIntegration: false }); + const logging = logLevel === 'debug' ? { logLevel: 'DEBUG'} : {}; + this.loadTelemetryLibrary(options.config.key, options.config.url, { integrations: { All: false }, loadIntegration: false, ...logging}); this.telemetry.identify(instanceId); + this.flushPageEvents(); } } @@ -66,10 +74,26 @@ class Telemetry { } } - page(category?: string, name?: string | undefined | null) { + page(category?: string, name?: string | null) { if (this.telemetry) { this.telemetry.page(category, name); } + else { + this.pageEventQueue.push({ + category, + name, + }); + } + } + + flushPageEvents() { + const queue = this.pageEventQueue; + this.pageEventQueue = []; + queue.forEach(({category, name}) => { + if (this.telemetry) { + this.telemetry.page(category, name); + } + }); } trackNodesPanel(event: string, properties: IDataObject = {}) { diff --git a/packages/editor-ui/src/store.ts b/packages/editor-ui/src/store.ts index e659587710..804a348e01 100644 --- a/packages/editor-ui/src/store.ts +++ b/packages/editor-ui/src/store.ts @@ -12,7 +12,6 @@ import { INodeIssueData, INodeTypeDescription, IRunData, - ITelemetrySettings, ITaskData, IWorkflowSettings, } from 'n8n-workflow'; @@ -89,7 +88,6 @@ const state: IRootState = { }, sidebarMenuItems: [], instanceId: '', - telemetry: null, }; const modules = { @@ -545,9 +543,6 @@ export const store = new Vuex.Store({ setInstanceId(state, instanceId: string) { Vue.set(state, 'instanceId', instanceId); }, - setTelemetry(state, telemetry: ITelemetrySettings) { - Vue.set(state, 'telemetry', telemetry); - }, setOauthCallbackUrls(state, urls: IDataObject) { Vue.set(state, 'oauthCallbackUrls', urls); }, @@ -659,10 +654,6 @@ export const store = new Vuex.Store({ return state.workflow.id === PLACEHOLDER_EMPTY_WORKFLOW_ID; }, - isTelemetryEnabled: (state) => { - return state.telemetry && state.telemetry.enabled; - }, - currentWorkflowHasWebhookNode: (state: IRootState): boolean => { return !!state.workflow.nodes.find((node: INodeUi) => !!node.webhookId); }, @@ -730,9 +721,6 @@ export const store = new Vuex.Store({ versionCli: (state): string => { return state.versionCli; }, - telemetry: (state): ITelemetrySettings | null => { - return state.telemetry; - }, oauthCallbackUrls: (state): object => { return state.oauthCallbackUrls; }, diff --git a/packages/editor-ui/src/views/NodeView.vue b/packages/editor-ui/src/views/NodeView.vue index e20fc28159..f46a28e753 100644 --- a/packages/editor-ui/src/views/NodeView.vue +++ b/packages/editor-ui/src/views/NodeView.vue @@ -2752,7 +2752,6 @@ export default mixins( }); this.$externalHooks().run('nodeView.mount'); - this.$telemetry.page('Editor', this.$route.name); }, destroyed () {