내부 이벤트 추적 빠른 시작
더 효율적이고 확장 가능하며 통합된 추적 API를 제공하기 위해 GitLab은 기존의 RedisHLL 및 Snowplow 추적을 폐기하고 있습니다. 대신, 새로운 track_event
(백엔드) 및 trackEvent
(프론트엔드) 메서드를 구현하고 있습니다. 이 접근 방식으로 RedisHLL 카운터를 업데이트하고 기존 구현에 대해 걱정 없이 Snowplow 이벤트를 보낼 수 있습니다.
내부 이벤트 추적을 코드에 적용하려면 다음 세 가지 작업을 수행해야 합니다.
- 이벤트 정의
- 하나 이상의 메트릭 정의
- 이벤트 트리거
이벤트 및 메트릭 정의
이벤트 및/또는 메트릭 정의를 만들려면 gitlab
디렉터리의 internal_events
생성기를 사용하십시오.
ruby scripts/internal_events/cli.rb
이 CLI를 사용하면 특정 사용 사례에 기반한 올바른 정의 파일을 생성해 주고, 이에 대한 코드 예제와 테스트를 제공합니다.
이벤트는 <action>_<target_of_action>_<where/when>
형식으로 명명되어야 합니다. 유효한 예시는 create_ci_build
또는 click_previous_blame_on_blob_page
입니다.
이벤트 트리거
이벤트를 트리거하여 메트릭을 업데이트하는 방법은 백엔드와 프론트엔드에서 약간 다릅니다. 아래 관련 섹션을 참조하십시오.
백엔드 추적
이벤트를 트리거하려면 Gitlab::InternalEventsTracking
모듈에서 track_internal_event
메서드를 호출하여 원하는 인수를 전달하십시오.
include Gitlab::InternalEventsTracking
track_internal_event(
"create_ci_build",
user: user,
namespace: namespace,
project: project
)
이 메서드는 자동으로 이벤트 create_ci_build
에 관련된 모든 RedisHLL 메트릭을 증가시키고, 명명된 인수 및 표준 컨텍스트(SaaS 전용)와 함께 해당 Snowplow 이벤트를 보냅니다. 또한 이벤트를 트리거하는 클래스의 이름은 Snowplow 이벤트의 category
속성에 저장됩니다.
unique: project.id
와 같이 고유
속성이있는 메트릭을 정의했다면 project
인수를 제공해야 합니다.
가능한 한 많은 수의 user
, namespace
, project
를 작성하는 것이 좋으며, 이는 데이터 품질을 높이고 향후 메트릭을 정의하기 쉽도록 만듭니다.
namespace
를 제공하지 않고 project
만 제공하는 경우, 이벤트의 namespace
로 project.namespace
가 사용됩니다.
명시적으로 category
를 지정하거나 전혀 제공하려는 경우 모듈을 사용하는 대신 InternalEvents.track_event
메서드를 직접 호출할 수 있습니다.
한 기능이 여러 네임스페이스를 통해 활성화되는 경우 이 기능이 왜 활성화되는지 추적해야 할 수도 있으므로 선택적으로 feature_enabled_by_namespace_ids
매개변수를 사용하여 네임스페이스 ID 배열을 전달할 수 있습니다.
track_internal_event(
...
feature_enabled_by_namespace_ids: [namespace_one.id, namespace_two.id]
)
추가 속성
추적 이벤트 시 추가 속성을 전달할 수 있습니다. 이 속성은 주어진 이벤트와 관련된 추가 데이터를 저장하는 데 사용할 수 있습니다. label
(문자열), property
(문자열) 및 value
(숫자) 키를 사용하여 최대 세 가지 추가 속성을 전송할 수 있습니다.
추가 속성은 additional_properties
해시를 #track_event
호출에 포함시켜 전달됩니다.
track_internal_event(
"create_ci_build",
user: user,
additional_properties: {
label: 'scheduled',
value: 20
}
)
컨트롤러 및 API 도우미
컨트롤러에 대해 내부 이벤트를 추적하기위한 ProductAnalyticsTracking
도우미 모듈이 있으며, #track_internal_event
를 호출하여 특정 컨트롤러 작업에 대한 내부 이벤트를 추적할 수 있습니다.
class Projects::PipelinesController < Projects::ApplicationController
include ProductAnalyticsTracking
track_internal_event :charts, name: 'visit_charts_on_ci_cd_pipelines', conditions: -> { should_track_ci_cd_pipelines? }
def charts
...
end
private
def should_track_ci_cd_pipelines?
params[:chart].blank? || params[:chart] == 'pipelines'
end
end
이벤트를 추적할 수 있도록 도우미가 현재 프로젝트와 네임스페이스를 얻을 수 있도록 컨트롤러 몸체에 이 두 메서드를 추가해야 합니다.
private
def tracking_namespace_source
project.namespace
end
def tracking_project_source
project
end
또한 API 도우미도 있습니다.
track_event(
event_name,
user: current_user,
namespace_id: namespace_id,
project_id: project_id
)
프론트엔드 추적
프론트엔드 추적 호출은 현재 페이지의 컨텍스트에서 user.id
, namespace.id
, project.id
값을 자동으로 전달합니다.
extra
, context
, label
, property
, value
와 같은 추가 속성을 전달해야 하는 경우 사용 안 함으로 표시된 snowplow 구현을 사용할 수 있습니다. 이 경우 내부 이벤트에 대한 피드백 이슈에 특정 사용 사례에 대해 알려주십시오.
Vue 컴포넌트
Vue 컴포넌트에서 추적을 사용하려면 Vue mixin을 사용할 수 있습니다.
Vue 컴포넌트 추적을 구현하려면:
-
InternalEvents
라이브러리를 가져와mixin
메서드를 호출합니다.import { InternalEvents } from '~/tracking'; const trackingMixin = InternalEvents.mixin();
-
컴포넌트에서 mixin을 사용합니다.
export default { mixins: [trackingMixin], data() { return { expanded: false, }; }, };
-
trackEvent
메서드를 호출합니다. 추적 옵션을 두 번째 매개변수로 전달할 수 있습니다.this.trackEvent('click_previous_blame_on_blob_page');
또는 템플릿에서
trackEvent
메서드를 사용할 수 있습니다.<template> <div> <button data-testid="toggle" @click="toggle">토글</button> <div v-if="expanded"> <p>Hello world!</p> <button @click="trackEvent('click_previous_blame_on_blob_page')">다른 이벤트 추적</button> </div> </div> </template>
Raw JavaScript
임의의 프론트엔드 JavaScript 코드에서 이벤트를 직접 추적하기 위해 JavaScript 모듈이 제공됩니다. 이 모듈은 믹스인을 사용할 수없는 컴포넌트 컨텍스트 외부에서 사용할 수 있습니다.
import { InternalEvents } from '~/tracking';
InternalEvents.trackEvent('click_previous_blame_on_blob_page');
Data-event 속성
이 속성은 GitLab 내부 이벤트를 버튼에 대해 추적하려는 경우 JavaScript 코드를 클릭 핸들러에 작성할 필요가 없습니다. 대신 이벤트 값과 함께 data-event-tracking
속성을 추가하면 됩니다. 이는 HAML 뷰와 함께 사용할 수도 있습니다.
<gl-button
data-event-tracking="click_previous_blame_on_blob_page"
>
클릭
</gl-button>
Haml
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle', data: { event_tracking: 'click_previous_blame_on_blob_page' }}) do
렌더링시 내부 이벤트
가끔 컴포넌트가 렌더링되거나 로드될 때 내부 이벤트를 보내고 싶을 때가 있습니다. 이러한 경우에는 data-event-tracking-load="true"
속성을 추가할 수 있습니다:
= render Pajamas::ButtonComponent.new(button_options: { data: { event_tracking_load: 'true', event_tracking: 'click_previous_blame_on_blob_page' } }) do
= _("New project")
추가 속성
추가로, 추적 이벤트를 할 때 추가 속성을 전달할 수 있습니다. 특정 이벤트와 관련된 추가 데이터를 저장하는 데 사용할 수 있습니다. label
(문자열), property
(문자열), value
(숫자) 키를 가진 추가 속성을 최대 3개까지 보낼 수 있습니다.
Vue 믹스인의 경우:
this.trackEvent('click_view_runners_button', {
label: 'group_runner_form',
property: dynamicPropertyVar,
value: 20
});
원시 자바스크립트의 경우:
InternalEvents.trackEvent('click_view_runners_button', {
label: 'group_runner_form',
property: dynamicPropertyVar,
value: 20
});
data-event 속성의 경우:
<gl-button
data-event-tracking="click_view_runners_button"
data-event-label="group_runner_form"
:data-event-property=dynamicPropertyVar
>
Click Me
</gl-button>
Haml의 경우:
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle', data: { event_tracking: 'action', event_label: 'group_runner_form', event_property: dynamic_property_var, event_value: 2 }}) do
프론트엔드 테스트
코드 중 trackEvent
메서드를 사용하는 경우, 원시 자바스크립트이든 Vue 컴포넌트이든 useMockInternalEventsTracking
헬퍼 메서드를 사용하여 trackEvent
가 호출되었는지 확인할 수 있습니다.
예를 들어, 아래 Vue 컴포넌트를 테스트해야 하는 경우,
<script>
import { GlButton } from '@gitlab/ui';
import { InternalEvents } from '~/tracking';
import { __ } from '~/locale';
export default {
components: {
GlButton,
},
mixins: [InternalEvents.mixin()],
methods: {
handleButtonClick() {
// 애플리케이션 로직
// 특정 이벤트 발생 시 추적 호출
this.trackEvent('click_view_runners_button', {
label: 'group_runner_form',
property: 'property_value',
value: 3,
});
},
},
i18n: {
button1: __('샘플 버튼'),
},
};
</script>
<template>
<div style="display: flex; height: 90vh; align-items: center; justify-content: center">
<gl-button class="sample-button" @click="handleButtonClick">
{{ $options.i18n.button1 }}
</gl-button>
</div>
</template>
해당 컴포넌트에 대한 테스트 케이스는 아래와 같을 것입니다.
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DeleteApplication from '~/admin/applications/components/delete_application.vue';
import { useMockInternalEventsTracking } from 'helpers/tracking_internal_events_helper';
describe('DeleteApplication', () => {
/** @type {import('helpers/vue_test_utils_helper').ExtendedWrapper} */
let wrapper;
const createComponent = () => {
wrapper = shallowMountExtended(DeleteApplication);
};
beforeEach(() => {
createComponent();
});
describe('sample button 1', () => {
const { bindInternalEventDocument } = useMockInternalEventsTracking();
it('sample button을 클릭했을 때 trackEvent 메서드를 호출해야 합니다', async () => {
const { trackEventSpy } = bindInternalEventDocument(wrapper.element);
await wrapper.find('.sample-button').vm.$emit('click');
expect(trackEventSpy).toHaveBeenCalledWith(
'click_view_runners_button',
{
label: 'group_runner_form',
property: 'property_value',
value: 3,
},
undefined,
);
});
});
});
Vue/View 템플릿에서 추적 속성을 사용하는 경우,
<script>
import { GlButton } from '@gitlab/ui';
import { InternalEvents } from '~/tracking';
import { __ } from '~/locale';
export default {
components: {
GlButton,
},
mixins: [InternalEvents.mixin()],
i18n: {
button1: __('샘플 버튼'),
},
};
</script>
<template>
<div style="display: flex; height: 90vh; align-items: center; justify-content: center">
<gl-button
class="sample-button"
data-event-tracking="click_view_runners_button"
data-event-label="group_runner_form"
>
{{ $options.i18n.button1 }}
</gl-button>
</div>
</template>
해당 컴포넌트에 대한 테스트 케이스는 아래와 같을 것입니다.
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DeleteApplication from '~/admin/applications/components/delete_application.vue';
import { useMockInternalEventsTracking } from 'helpers/tracking_internal_events_helper';
describe('DeleteApplication', () => {
/** @type {import('helpers/vue_test_utils_helper').ExtendedWrapper} */
let wrapper;
const createComponent = () => {
wrapper = shallowMountExtended(DeleteApplication);
};
beforeEach(() => {
createComponent();
});
describe('sample button', () => {
const { bindInternalEventDocument } = useMockInternalEventsTracking();
it('sample button을 클릭했을 때 trackEvent 메서드를 호출해야 합니다', () => {
const { triggerEvent, trackEventSpy } = bindInternalEventDocument(wrapper.element);
triggerEvent('.sample-button');
expect(trackEventSpy).toHaveBeenCalledWith('click_view_runners_button', {
label: 'group_runner_form',
});
});
});
});