除雪車トラッキングの導入

このページでは、以下の方法について説明します:

  • Snowplowのフロントエンドとバックエンドのトラッキングの実装
  • Snowplow イベントのテスト

イベント定義

フロントエンド、バックエンドに関係なく、すべてのSnowplowイベントは対応するイベント定義を必要とします。これらの定義はイベントとそのプロパティを文書化し、メンテナーと分析を容易にします。これらの定義はイベント辞書で参照できます。イベント辞書ガイドに、イベント定義の設定方法が記載されています。

Snowplow JavaScriptフロントエンドのトラッキング

GitLabはカスタムイベントをトラッキングするためにSnowplow JavaScriptトラッカーをラップするTracking インターフェースを提供します。

推奨されるフロントエンドのトラッキング実装については、Usage recommendationsをご覧ください。

構造化イベントとページビューは、gitlab_standard コンテキストを含み、デフォルトデータをベースとして含むwindow.gl.snowplowStandardContext オブジェクトを使用します:

物件概要物件例
context_generated_at"2022-01-01T01:00:00.000Z"
environment"production"
extra{}
namespace_id123
plan"gold"
project_id456
source"gitlab-rails"
user_id 789*
is_gitlab_team_membertrue

* コレクターレベルで仮名化処理を行います。

これらのプロパティは、source (gitlab-javascript)、google_analytics_id およびカスタムのextra オブジェクトのように、frontend 固有の値でオーバーライドされます。後続の構造化イベントが発生した場合は、このオブジェクトを変更できます。

トラッキングの実装は、actioncategory を持たなければなりません。キーと値のペアを受け付けるextra オブジェクトに加えて、イベントスキーマから追加のプロパティを提供することができます。

物件概要種類デフォルト値説明
category文字列です。document.body.dataset.pageイベントがキャプチャされるページのページまたはサブセクション。
action文字列です。'generic'ユーザーのアクション。クリックはclick で、アクティビティはactivate でなければなりません。例えば、フォームフィールドへのフォーカスはactivate_form_input で、ボタンのクリックはclick_button です。
dataオブジェクトを返します。{} イベントスキーマに記載されているlabelpropertyvalue 、カスタムコンテキスト用のcontextextra (キーと値のペアオブジェクト)などの追加データ。

推奨使用法

  • click,show.bs.dropdown,hide.bs.dropdown イベントを発する HTML 要素にはdata 属性を使いましょう。
  • カスタムイベントをトラッキングする場合や、data 属性でサポートされているイベントが伝播しない場合は、Vue mixinを使用してください。たとえば、click を発信しないクリッカブル・コンポーネントなどです。
  • バニラJavaScriptファイルでトラッキングを行う場合は、トラッキングクラスを使用してください。

データ属性トラッキングの実装

HAML や Vue テンプレートにトラッキングを実装するには、data-track 属性 を要素に追加します。

次の例では、data-track-* 属性をボタンに割り当てています:

%button.btn{ data: { track_action: "click_button", track_label: "template_preview", track_property: "my-template" } }
<button class="btn"
  data-track-action="click_button"
  data-track-label="template_preview"
  data-track-property="my-template"
  data-track-extra='{ "template_variant": "primary" }'
/>

data-track 属性

属性必須説明
data-track-actiontrueユーザーが行っているアクション。クリックの前にはclick を、アクティビティの前にはactivate を付けなければなりません。例えば、フォームフィールドにフォーカスする場合はactivate_form_input 、ボタンをクリックする場合はclick_button となります。GitLab 13.11 で非推奨となったdata-track-event を置き換えるものです。
data-track-labelfalseアクションを実行する特定の要素またはオブジェクト。例えば、create_from_template の「Create from template」というラベルのタブなどです。テキストがない場合は一意の識別子、例えば、groups_dropdown_close の「Groups」ドロップダウンリストを閉じる場合などです。
data-track-propertyfalse作用する要素またはオブジェクトの追加プロパティ。
data-track-valuefalseイベントに直接関連する数値(10進数)を記述します。これは入力値である可能性があります。例えば、internal visibilityをクリックしたときの10 。省略された場合、これは要素のvalue プロパティまたはundefined になります。チェックボックスの場合、デフォルト値は要素のchecked属性か、チェックされていないときの0 。この値は、イベントを送信する前に数値として解析されます。
data-track-extrafalse有効な JSON 文字列として渡されるキーと値のペア・オブジェクト。この属性は、gitlab_standard スキーマのextra プロパティに追加されます。
data-track-contextfalse有効な JSON 文字列として渡されたカスタムコンテキストオブジェクトを追加します。

イベントリスナー

イベントリスナーは、データ属性を持つ要素のクリックイベントを処理するために、ドキュメントレベルでバインドします。これにより、DOM の再レンダリングや変更時にイベントを処理することができます。ドキュメントレベルのバインディングは、クリックイベントが DOM ツリーを伝搬しなくなる可能性を減らします。

クリックイベントが伝播しなくなる場合は、リスナーを実装し、Vue コンポーネント追跡または生の JavaScript 追跡を行う必要があります。

ヘルパーメソッド

以下のRubyヘルパーが使えます:

tracking_attrs(label, action, property) # { data: { track_label... } }

tracking_attrs_data(label, action, property) # { track_label... }

HAML テンプレートでも使用できます:

%button{ **tracking_attrs('main_navigation', 'click_button', 'navigation') }

// When merging with additional data
// %button{ data: { platform: "...", **tracking_attrs_data('main_navigation', 'click_button', 'navigation') } }

GitLab ヘルパーメソッドnav_linkを使う場合は、キーワード引数のhtml_options 下で html_optionsラップする必要があります。ActionView ヘルパーメソッドlink_toを使う場合、html_options をラップする必要はありません。

# Bad
= nav_link(controller: ['dashboard/groups', 'explore/groups'], data: { track_label: "explore_groups",
track_action: "click_button" })

# Good
= nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { data: { track_label:
"explore_groups", track_action: "click_button" } })

# Good (other helpers)
= link_to explore_groups_path, title: _("Explore"), data: { track_label: "explore_groups", track_action:
"click_button" }

Vueコンポーネントトラッキングの実装

カスタムイベントのトラッキングには、Vue mixinを使用します。これは、track メソッドとしてTracking.event を公開します。トラッキングオプションを指定するには、tracking データオブジェクトまたはコンピューテッドプロパティを作成し、2番目のパラメータとしてthis.track('click_button', opts) を指定します。これらのオプションは、デフォルトをオーバーライドし、プロップからの動的な値やステートに基づく値を指定できます:

プロパティタイプデフォルト  category文字列document.body.dataset.page'code_quality_walkthrough'label文字列'''process_start_button'property文字列'' 'asc' または'desc'  value整数undefined 0,1,500 extraオブジェクト{}{ selectedVariant: this.variant }

Vueコンポーネントのトラッキングを実装するには

  1. Tracking ライブラリをインポートし、mixin メソッドを呼び出します:

    import Tracking from '~/tracking';
       
    const trackingMixin = Tracking.mixin();
       
    // Optionally provide default properties
    // const trackingMixin = Tracking.mixin({ label: 'right_sidebar' });
    
  2. コンポーネントで mixin を使用します:

    export default {
      mixins: [trackingMixin],
      // Or
      // mixins: [Tracking.mixin()],
      // mixins: [Tracking.mixin({ label: 'right_sidebar' })],
       
      data() {
        return {
          expanded: false,
        };
      },
    };
    
  3. tracking データオブジェクトやコンピューテッドプロパティを作成することで、トラッキングオプションを指定することができます:

    export default {
      name: 'RightSidebar',
       
      mixins: [Tracking.mixin()],
       
      data() {
        return {
          expanded: false,
          variant: '',
          tracking: {
            label: 'right_sidebar',
            // property: '',
            // value: '',
            // experiment: '',
            // extra: {},
          },
        };
      },
       
      // Or
      // computed: {
      //   tracking() {
      //     return {
      //       property: this.variant,
      //       extra: { expanded: this.expanded },
      //     };
      //   },
      // },
    };
    
  4. track メソッドを呼び出します。トラッキングオプションは2番目のパラメータとして渡すことができます:

    this.track('click_button', {
      label: 'right_sidebar',
    });
    

    または、テンプレート内部でtrack メソッドを使用します:

    <template>
      <div>
        <button data-testid="toggle" @click="toggle">Toggle</button>
       
        <div v-if="expanded">
          <p>Hello world!</p>
          <button @click="track('click_button')">Track another event</button>
        </div>
      </div>
    </template>
    

テスト例

export default {
  name: 'CountDropdown',

  mixins: [Tracking.mixin({ label: 'count_dropdown' })],

  data() {
    return {
      variant: 'counter',
      count: 0,
    };
  },

  methods: {
    handleChange({ target }) {
      const { variant } = this;

      this.count = Number(target.value);

      this.track('change_value', {
        value: this.count,
        extra: { variant }
      });
    },
  },
};
import { mockTracking } from 'helpers/tracking_helper';
// mockTracking(category, documentOverride, spyMethod)

describe('CountDropdown.vue', () => {
  let trackingSpy;
  let wrapper;

  ...

  beforeEach(() => {
    trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
  });

  const findDropdown = () => wrapper.find('[data-testid="dropdown"]');

  it('tracks change event', () => {
    const dropdown = findDropdown();
    dropdown.element.value = 30;
    dropdown.trigger('change');

    expect(trackingSpy).toHaveBeenCalledWith(undefined, 'change_value', {
      value: 30,
      label: 'count_dropdown',
      extra: { variant: 'counter' },
    });
  });
});

生のJavaScriptトラッキングの実装

バニラJavaScriptファイルからトラッキングを行うには、Tracking.event 静的関数を使用します(dispatchSnowplowEventを呼び出します)。

次の例では、手動でTracking.event を呼び出すことで、ボタンのクリックを追跡しています。

import Tracking from '~/tracking';

const button = document.getElementById('create_from_template_button');

button.addEventListener('click', () => {
  Tracking.event(undefined, 'click_button', {
    label: 'create_from_template',
    property: 'template_preview',
    extra: {
      templateVariant: 'primary',
      valid: 1,
    },
  });
});

テスト例

import Tracking from '~/tracking';

describe('MyTracking', () => {
  let wrapper;

  beforeEach(() => {
    jest.spyOn(Tracking, 'event');
  });

  const findButton = () => wrapper.find('[data-testid="create_from_template"]');

  it('tracks event', () => {
    findButton().trigger('click');

    expect(Tracking.event).toHaveBeenCalledWith(undefined, 'click_button', {
      label: 'create_from_template',
      property: 'template_preview',
      extra: {
        templateVariant: 'primary',
        valid: true,
      },
    });
  });
});

フォームトラッキング

Snowplowの自動フォームトラッキングを有効にします:

  1. DOM の準備ができたらTracking.enableFormTracking に電話してください。
  2. 以下の要素の少なくとも1つを含むconfig オブジェクトを用意してください:
    • forms 追跡するフォームを決定します。CSS クラス名で識別されます。
    • fields は、追跡するフォーム内のフィールドを決定します。フィールドname によって識別されます。
  3. オプション。第 2 引数にコンテキストのリストを指定します。gitlab_standard スキーマはこれらのイベントから除外されます。
Tracking.enableFormTracking({
  forms: { allow: ['sign-in-form', 'password-recovery-form'] },
  fields: { allow: ['terms_and_conditions', 'newsletter_agreement'] },
});

テスト例

import Tracking from '~/tracking';

describe('MyFormTracking', () => {
  let formTrackingSpy;

  beforeEach(() => {
    formTrackingSpy = jest
      .spyOn(Tracking, 'enableFormTracking')
      .mockImplementation(() => null);
  });

  it('initialized with the correct configuration', () => {
    expect(formTrackingSpy).toHaveBeenCalledWith({
      forms: { allow: ['sign-in-form', 'password-recovery-form'] },
      fields: { allow: ['terms_and_conditions', 'newsletter_agreement'] },
    });
  });
});

Rubyバックエンドトラッキングの実装

Gitlab::Tracking は、カスタムイベントをトラッキングするためにSnowplow Ruby Trackerをラップするインタフェースです。バックエンドトラッキングは以下を提供します:

  • ユーザー行動のトラッキング
  • コードのセクションやアスペクトのパフォーマンスを経時的に監視し、可視化するためのインストルメンテーション。

カスタムのイベントトラッキングとインスツルメンテーションを追加するには、GitLab::Tracking.event クラスメソッドをコールします。例えば

class Projects::CreateService < BaseService
  def execute
    project = Project.create(params)

    Gitlab::Tracking.event('Projects::CreateService', 'create_project', label: project.errors.full_messages.to_sentence,
                           property: project.valid?.to_s, project: project, user: current_user, namespace: namespace)
  end
end

以下の引数を使用します:

引数種類デフォルト値説明
category文字列 アプリケーションの領域または側面。例えば、HealthCheckController またはLfs::FileTransformer
action文字列 実行されるアクション。たとえば、create のようなコントローラのアクションや、Active Record のコールバックなど。
label文字列nil動作させる特定の要素またはオブジェクト。これは次のいずれかになります: 要素のラベル (たとえば、create_from_template の「テンプレートから作成」というラベルの付いたタブ); テキストがない場合の一意の識別子 (たとえば、グループ ドロップダウン リストを閉じるためのgroups_dropdown_close ); または作成されるレコードの名前またはタイトル属性。
property文字列nil作用する要素またはオブジェクトの追加プロパティ。
value数値nilイベントに直接関連する数値(10進数)を記述します。これは入力値である可能性があります。例えば、internal visibilityをクリックしたときの10
contextArray[SelfDescribingJSON]nilこのイベントで送信するカスタムコンテキストの配列。ほとんどのイベントはカスタムコンテキストを持つべきではありません。
projectプロジェクトnilイベントに関連するプロジェクト。
userユーザーnilイベントに関連付けられたユーザー。この値はコレクターレベルで仮名化処理を受けます。
namespace名前空間nilイベントに関連付けられた名前空間。
extraハッシュ{}追加のキーワード引数はハッシュに集められ、イベントと共に送信されます。

ユニットテスト

バックエンドの Snowplow イベントをテストするには、expect_snowplow_event ヘルパーを使用します。詳細については、テストのベストプラクティスを参照してください。

パフォーマンス

イベントをトラッキングする際にはAsyncEmitterを使用し、インストルメンテーション・コールをバックグラウンド・スレッドで実行できるようにしています。これはまだ開発中のアクティブな領域です。

Snowplowの開発とテスト

Snowplowイベントを開発しテストするために、フロントエンドとバックエンドのイベントをテストするツールがいくつかあります:

テストツールフロントエンドトラッキングバックエンドトラッキングローカル開発者環境生産環境生産環境
Snowplow AnalyticsデバッガChrome拡張機能はいなしはいはいはい
Snowplow Inspector Chrome 拡張機能はいなしはいはいはい
スノープラウ・マイクロはいはいはいなしなし

テストフロントエンドイベント

開発者がフロントエンドのイベントをテストする前に、次のことが必要です:

  1. 管理エリアでSnowplowトラッキングを有効にします。
  2. お使いの環境でSnowplow JavaScriptのロードを妨げる可能性のある広告ブロッカーをオフにしてください。
  3. ブラウザの「Do Not Track」(DNT) をオフにしてください。

URLはすべて仮名です。エンティティ識別子は、個人を特定できる情報(PII) を置き換えます。PII には、ユーザー名、グループ名、プロジェクト名が含まれます。同じ理由で、ページタイトルもGitLab としてハードコードされます。

Snowplow AnalyticsデバッガChrome拡張機能

Snowplow Analytics Debuggerはフロントエンドのイベントをテストするためのブラウザ拡張機能です。本番環境、ステージング環境、ローカル開発環境で動作します。

  1. Snowplow Analytics DebuggerChrome ブラウザ拡張機能をインストールしてください。
  2. Chrome DevToolsを開き、Snowplow Analytics Debuggerタブを開きます。

Snowplow Inspector Chrome 拡張機能

Snowplow Inspector Chrome Extensionはフロントエンドのイベントをテストするためのブラウザ拡張機能です。本番環境、ステージング環境、ローカル開発環境で動作します。

ビデオチュートリアルについては、Snowplowプラグインのウォークスルーを参照してください。

  1. Snowplow Inspectorをインストールします。
  2. 拡張機能を開くには、アドレスバーの横にあるSnowplow Inspectorアイコンを選択します。
  3. Snowplowのあるウェブページをクリックすると、インスペクタウィンドウでJavaScriptのイベントが発生するのを確認できます。

Snowplow Microでバックエンドイベントをテスト

Snowplow Microは、ローカル開発環境でバックエンドとフロントエンドをテストするためのDockerベースのソリューションです。Snowplow MicroはフルSnowplowパイプラインと同じイベントを記録します。イベントをクエリするには、Snowplow Micro APIを使用します。

GitLab Development Kit(GDK) を使って自動的にセットアップできます。詳細はハウツードキュメントを参照してください。

  1. 開発時にSnowplow Microを使うようにGDKに指示する環境変数を設定します。これはapplication_settings の2つのオプションを上書きします:
    • snowplow_enabled の設定は、true を返します。Gitlab::Tracking.enabled?
    • snowplow_collector_hostname を設定すると、代わりにGitlab::Tracking.collector_hostnameから常にlocalhost:9090 (またはsnowplow_micro.port GDK 設定で設定されているポート) を返します。 Snowplow Micro を設定すると、バックエンドの Snowplow イベントを手動でテストできるようになります:
  2. Railsコンソールからテスト用のSnowplowイベントを送信します:

    Gitlab::Tracking.event('category', 'action')
    
  3. localhost:9090/micro/good に移動してイベントを確認します。

トラブルシューティング

外部ホスト使用時のコンテンツセキュリティポリシー警告を制御するには、config/gitlab.yml を変更し、警告を許可または防止します。警告を許可するには、関連するホストをconnect_src に追加します。例えば、https://snowplow.trx.gitlab.net

development:
  <<: *base
  gitlab:
    content_security_policy:
      enabled: true
      directives:
        connect_src: "'self' http://localhost:* http://127.0.0.1:* ws://localhost:* wss://localhost:* ws://127.0.0.1:* https://snowplow.trx.gitlab.net/"