そのComponent本当に使われていますか？無料でできる測定方法 (LWC)

# 背景
ApexやComponentで、実際に1日に何回呼び出されて、どの部署の人に利用されているのか把握したい、というのがもともとあり、また誰にも使用されていないComponentが増え続けてしまう傾向があるので年末に向けて大掃除したい、という背景です。
# 概要
SalesforceにおけるAura/LWC Componentが実際にいつ誰に利用されているか、のログを取得していく方法です。ログ用のカスタムオブジェクトを作成して、そこにUserIdをOwnerIdにして、CreatedDateを利用して、１アクション、１レコードとして1日の時間などをログしていきます。
# 結果
当初はどのMethodがよく使用されているのか計測するためでしたが、実は誰が何時に働き始めたり、営業やサポートでどのオブジェクトをよく利用しているか、一元管理できることに気づきました。

ただ注意することはこの「ログ・イコール・パフォーマンス」ではないということです。KPI監視ツールではなく、あくまで活動のモニタとしては部門管理者にとってはとても有用なのではないかと試験運用中です。また全てをログしようとするとキリがないので、ある程度頻度を予見できるComponentから始めるといいでしょう。作成したComponentがよく利用されているのをみると、開発者としてはやはり嬉しいものです。

とはいえ、時間ごとの活動が可視化される点では、リモートワークで「仕事していないのかどうかわからない」という情報がリモートワークにより暗中模索で疑心暗鬼になるよりとても健全かという発見もありました。

![log-dashboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15524/2222ae08-c488-2380-504b-8dcbd0ac1feb.png)
例：朝7時から活動が始まり、お昼前に一旦ピークが来ます。午後は順々にエンジンがかかり3時にピークを迎えます。Division, Component, Owner Aliasなどでさらにフィルタした分析が即時にできます。

# 手順
手順としては以下：
1. Custom Obectを作成
2. Fieldsを作成
3. Apexで新規レコードMethodを作成
4. LWCでLogger Componentを作成
5. Aura, LWCに作成した Logger Component を埋め込む
6. Report, Dashboardで視覚化
7. フローで数日に一回は自動削除する（ログの量によりログ保持期間は異なる）
8. 最終点検

## 1. Custom Obectを作成
私はApex_Log__cと命名しましたが、単にLog__cでもいいかと思います。Enable Reportsを有効化しておくと後々のReport作成でサクッとReport・Dashboardへ移れます。またデータはPrivateで、Sharing Rulesに基づいてRoles & Subordinatesで自分、もしくは自分の配下を追加することで、マネージャーが自分の部署を見れて個々人は個人の記録のみ見れる、という設定も可能です。
## 2. Fieldsを作成
たくさん作成する必要はありませんが、後々Dashboardで分類分けや部門ごとの集計・フィルタなどであると便利な場合は、お好みで。実際は、Component以外のClass, Methodは開発者が知りたい情報なので、必要なければ省いても大丈夫です。Daysはスケジュールフローで行う一括削除のトリガになる情報なので必須です。
- Class__c (text)
- Component__c (text)
- Method__c (text)
- Created_Time__c (formula)	=> LEFT(TEXT(Timevalue(CreatedDate+9/24)),2)
- Days__c (formula) => TODAY()-DATEVALUE(CreatedDate)
- Division (formula) => CreatedBy.Division
- Note__c (text)
これで、ログを記載していく箱は完成です。
## 3. Apexで新規レコードMethodを作成
パラメーターが長いので警告をEditorの受けるかもしれませんが、気になる場合はMapで書き直してもいいかもしれません。とてもシンプルにこちらです。
```public with sharing class ApexLoggerController {
    @AuraEnabled
    public static void methodLogger(String className, String methodName, String componentName, String logNote){
        Apex_Log__c log = new Apex_Log__c(
            Class__c = className,
            Method__c = methodName,
            Component__c = componentName,
            Note__c = logNote
        );
        insert log;
    }
```
## 4. LWCで Logger Component を作成
LogをするためのLWC Comonentです。LWCで作成することによりすでに動いているAuraでもログが取れるようになります。こちらはhtml側は実際表示する必要はないので空です。
apexLogger.html 
```
<template>
</template>
```

apexLogger.js
```
import { LightningElement, api } from 'lwc';
import methodLogger from '@salesforce/apex/ApexLoggerController.methodLogger';

export default class ApexLogger extends LightningElement {
    // @api recordId In case you need a record Id
    @api className;
    @api methodName;
    @api componentName;
    @api logNote;
    
    connectedCallback() {
        this.handleLogging();
    }

    handleLogging() {
        methodLogger({
            className: this.className, 
            methodName: this.methodName,
            componentName: this.componentName,
            logNote: this.logNote
        })
            .then(result => {
                console.log('Logging complete:', result);
            })
            .catch(error => {
                console.error('Logging failed:', error);
            });
    }
}
```
ここまでが下準備です。

## 5. Aura, LWCに作成した Logger Component を埋め込む
ここから実際のLogger Componentを配置する段階に入っていきます。それぞれ呼び出されるComponentを「親Component」として、このLogger Componentを「子Component」として埋め込んでいきます。
### Auraの場合
.cmp
```
<!-- logger -->
(略)
<aura:attribute name="shouldLog" type="Boolean" default="false" />
<aura:attribute name="className" type="String" default="" />
<aura:attribute name="componentName" type="String" default="" />
<aura:attribute name="methodName" type="String" default="" />
<aura:attribute name="logNote" type="String" default="" />
(略)
<aura:if isTrue="{!v.shouldLog}">
    <c:apexLogger className="{!v.className}" methodName="{!v.methodName}" componentName="{!v.componentName}" logNote="{!v.logNote}" />
</aura:if>
```
:::note info
Component Nameはdefault値を入れていてもいいかもしれません。controllerやhelper側で上書きもできます。LWC Logger Componentはaura:ifにより表示・非表示が行われmethodが呼ばれることになります。（Logger Componentのhtmlは空なので見えるわけではありません）
:::
Controller.js
```
// logger 
const methodName = '{任意のmethod名}';
const className = '{任意のclass名}';
const componentName = '{任意のComponent名}'
const logNote = '{任意の付記情報}';
helper.handleLogger(cmp, methodName, className, componentName, logNote);
 ```
:::note info
こちらはよぶmethod名やGlobalのClassなどを呼ぶ際に記載したい場合は挿入できます。
:::

Helper.js
```
// logger 
handleLogger: function(cmp, methodName, className, componentName, logNote){
　　cmp.set('v.shouldLog', false); // initialize
　　cmp.set('v.methodName',methodName);
　　cmp.set('v.className',className);
　　cmp.set('v.componentName',componentName);
　　cmp.set('v.logNote', logNote);
　　cmp.set('v.shouldLog', true);
    },  
```
:::note info
パラメーターを設定すると同時に、shouldLogのAtributeでLogger Componentの表示を制御することになります。基本はhelperからshouldLog制御した方がのちのち各Controllerにあるmethodごとで異なった記述のログを取るときにhelper側をパラメーター付きで呼び出すだけなので記述が便利になります。単発の場合はController.jsからshouldLogを制御しても問題ないです。
:::

### LWCの場合
html
```
<template lwc:if={shouldLog}>
   <c-apex-logger class-name={className} method-name={methodName} component-name={componentName} log-note={logNote}></c-apex-logger>
</template>
```
:::note info
\<template lwc:if={shouldLog}> で4で作成したLogger Componentの表示非表示を制御することになります。Logger Componentを表示することでそこでapexのログ作成が走ります。
:::
```
//logger parameterのデフォルト値を設定
@track shouldLog  = false;
@track className  ='';
@track methodName ='';
@track componentName ='';
@track logNote =''; 
...
...
略
...

methodSomething() { // {新規/既存のどのメソッド内に埋め込んでください}
   this.className  ='{任意のClass名}';
   this.methodName ='{任意のMethod名}';
   this.componentName ='{任意のComponent名}';
   this.logNote ='{任意の付記情報}'; // アカウント名や商談名等自由に
   this.shouldLog = true; 
}
```
:::note info
呼び出されるたびにログを取りたいmethodの中で、パラメーターの値を設置し、shouldLogをtrueにすることでLogger Componentを表示します。そこでapexのログ作成が走ります。
:::

## 6. Report, Dashboardで視覚化
Custom Object作成の際、Enable Reportsを有効化しておく必要があります。カスタムフィールドのCreatedTimeは作成時の時間だけ2桁で保存してくれるので、この項目でグループ化すると1時間ごとのログ量としてグループ化するのに役立ちます。

この視覚化でわかるのは、Componentの部門ごとの使用頻度です。管理職はTarget Componentで予実達成度をよくチェックしていますし、営業はもちろんAccount, Opportunity, 管理はCaseやOverdueなど債権管理などもよく利用しています。一般職でもTarget Componentをよく閲覧する人もいるので、経営的視点に経っている意識が高いのかもしれないと意外な発見もあります。各LayoutにおけるComponentの配置への参考にもなります。

更に、DashboardのFilterを追加すると、どのComponentが「誰にいつ使用されているか」、誰が「いつ活動してどのComponentを利用しているか」など条件付きの横串で手軽に見れるのでとても便利です。

## 7. フローで数日に一回は自動削除する
小さい組織でログポイントの埋め込みも少なければ数日保持していてもいいですが、あまり多くの場所や多くの人数が利用する組織ですと、レコードがストレージを圧迫する可能性があります。参考として、1レコードおよそ2KBなので添付ファイルに比べればそうそうストレージを気にする必要はありませんが、700-900レコードぐらいでしたら３日ぐらいの保持期間をみておくと直近の分析では足ります。

定期的に自動削除をするには、スケジュールフローで行います。設定はとてもシンプルで、1.で作成したオブジェクトを対象にShedule-Triggered Flowを作成します。条件にFieldsで作成したDays__cを利用します。これは作成日から今日までの日付を数値で表します。この例では、作成日から3日を過ぎていたら削除というフローです。

![schedule-triggered-flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15524/708965d6-29ff-c747-211f-e4e1500d3102.png)

![schedule-triggered-flow-condition.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15524/2e33e6f1-5172-c5fe-b2ca-6ca3c41ea148.png)

## 8. 最終点検
- Classは利用者すべてに付与されているか
- Custom ObjectのEnable Reportsは有効化されているか
- RoleによるSharing Rulesは適用されているか

以上になります。年の瀬に皆様のClass, Method, Componentの大掃除にもお役に立てれば幸せです。次回はEmail-to-Caseでスパムにお困りの方向けのSpam対策を書こうかと思います。