[OutSystems]Logデータを直接確認する方法


OutSystemsで発生するログは、通常はService Centerから確認します。
しかし、何らかの障害でService Centerにログイン出来ないときや、Service Centerで確認できない古いログを確認したいときのために、OutSystemsのログの仕組みを再確認してみます。
ただし、Personal Environmentでは、DBに直接アクセスできないため、DBレベルの情報は実地に確認できていません。

ちなみに、Service Centerで確認ログは、最長で直近２週間（金曜夜間切り替え）のように見えます。残念ながらドキュメントは見当たらないのですが。ちなみに、この期間は以下に書くログの仕組みと符合しますね。

# OutSystemsのログ保管の仕組み
ログ種別毎に別のテーブルがあり、各ログはOutSystemsによって自動的に記録されています。
（LogMessage Actionを使って任意に記録することも可能。これはGeneralログに記録）

そして、このログテーブルのセットが週毎に１セット、合計で10セットあります。
このセットの数字は各テーブル名のサフィックスとして「_N」のようにつく（Nは0-9の数字）。
例えば、Errorログは「oslog_Error_0」。

各ログ種別毎に今週のログ、前週のログを閲覧するためのビューがあります。
また、この週の切り替えは、毎週金曜日夜11:45に起こるとのこと。

ここに書いたことは正式には、[ログのテーブルおよびビュー](https://success.outsystems.com/ja-jp/Documentation/11/Managing_the_Applications_Lifecycle/Monitor_and_Troubleshoot/Logging_database_and_architecture/The_log_tables_and_views)で確認できます。

# ログ種別毎のビュー
各環境にデフォルトでインストールされているPlatformLogs Extensionにログアクセス用のEntity群があります。
このEntityは当週または前週のログを確認するためのビューを参照しています。

つまり、Service Centerで見られるようなログはこのExtensionのEntityを使って閲覧・検索できる仕組みを作れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/df44ec2b-5a37-1c48-6766-a2ecdaecee07.png)


サフィックス「_Previous」がついているのが前週分、ついていないのが今週分です。
ビュー定義は、週次バッチ（金曜夜）のタイミングで作り変えられて、新しいセットを指すようになるそうです。

PlatformLogs Extension内のEntity名とビュー名の対比表（「Extension」Entityと「Entity」Entityをジョインして得た）

| Entity名 | ビュー名 |
|:---------|:---------------|
| Log_Cyclic_Job | OSLOG_CYCLIC_JOB |
| Log_Cyclic_Job_Previous | OSLOG_CYCLIC_JOB_PREVIOUS |
| Log_Error | OSLOG_ERROR |
| Log_Error_Previous | OSLOG_ERROR_PREVIOUS |
| Log_Extension | OSLOG_EXTENSION |
| Log_Extension_Previous | OSLOG_EXTENSION_PREVIOUS |
| Log_General | OSLOG_GENERAL |
| Log_General_Previous | OSLOG_GENERAL_PREVIOUS |
| Log_Integration | OSLOG_INTEGRATION |
| Log_Integration_Detail | OSLOG_INT_DETAIL |
| Log_Integration_Detail_Previous | OSLOG_INT_DETAIL_PREVIOUS |
| Log_Integration_Previous | OSLOG_INTEGRATION_PREVIOUS |
| Log_Mobile_Request | OSLOG_MOBILE_REQUEST |
| Log_Mobile_Request_Detail | OSLOG_MR_DETAIL |
| Log_Mobile_Request_Detail_Previous | OSLOG_MR_DETAIL_PREVIOUS |
| Log_Mobile_Request_Previous | OSLOG_MOBILE_REQUEST_PREVIOUS |
| Log_RequestEvent | OSLOG_REQUESTEVENT |
| Log_RequestEvent_Previous | OSLOG_REQUESTEVENT_PREVIOUS |
| Log_Screen | OSLOG_SCREEN |
| Log_Screen_Previous | OSLOG_SCREEN_PREVIOUS |
| Log_ServiceAPI | OSLOG_SRVAPI |
| Log_ServiceAPI_Detail | OSLOG_SRVAPI_DETAIL |
| Log_ServiceAPI_Detail_Previous | OSLOG_SRVAPI_DETAIL_PREVIOUS |
| Log_ServiceAPI_Previous | OSLOG_SRVAPI_PREVIOUS |
| Log_Web_Reference | OSLOG_WEB_REFERENCE |
| Log_Web_Reference_Previous | OSLOG_WEB_REFERENCE_PREVIOUS |
| Log_Web_Service | OSLOG_WEB_SERVICE |
| Log_Web_Service_Previous | OSLOG_WEB_SERVICE_PREVIOUS |

各ビューの列定義については[ログデータに関するレファレンス](https://success.outsystems.com/ja-jp/Documentation/11/Managing_the_Applications_Lifecycle/Monitor_and_Troubleshoot/Logging_database_and_architecture/Log_data_reference)を参照。

# ログ種別ごとの物理テーブル
2つのビューで見られない古いログを見るには、テーブルを直接見なければいけません（あるいはバッチを作って別の場所に退避しておく）。

そのテーブルは、Forgeにある[Logs Manager](https://www.outsystems.com/forge/component-overview/1195/logs-management)に含まれるExtension「LogsManagementDBLogsAcces」を経由してアクセスできます。

また、Extensionがあるので、ビューと同様に（「Extension」Entityと「Entity」Entityをジョイン）してテーブルの物理名を得ることができました。

FilterでExtension名を指定しますが、どうもExtension名にタイプミスがあるようなので自分で試すときには気をつけて下さい。
以下の表は、Personal Environmentで実行したときの出力例（テーブル名はSQL Serverの表現になっていますね）。

| Entity名 | 物理テーブル名 |
|:---------|:---------------|
| Log_Cyclic_Job_0 | [dbo].[oslog_Cyclic_Job_0] |
| Log_Cyclic_Job_1 | [dbo].[oslog_Cyclic_Job_1] |
| Log_Cyclic_Job_2 | [dbo].[oslog_Cyclic_Job_2] |
| Log_Cyclic_Job_3 | [dbo].[oslog_Cyclic_Job_3] |
| Log_Cyclic_Job_4 | [dbo].[oslog_Cyclic_Job_4] |
| Log_Cyclic_Job_5 | [dbo].[oslog_Cyclic_Job_5] |
| Log_Cyclic_Job_6 | [dbo].[oslog_Cyclic_Job_6] |
| Log_Cyclic_Job_7 | [dbo].[oslog_Cyclic_Job_7] |
| Log_Cyclic_Job_8 | [dbo].[oslog_Cyclic_Job_8] |
| Log_Cyclic_Job_9 | [dbo].[oslog_Cyclic_Job_9] |
| Log_Error_0 | [dbo].[osLog_Error_0] |
| Log_Error_1 | [dbo].[osLog_Error_1] |
| Log_Error_2 | [dbo].[osLog_Error_2] |
| Log_Error_3 | [dbo].[osLog_Error_3] |
| Log_Error_4 | [dbo].[osLog_Error_4] |
| Log_Error_5 | [dbo].[osLog_Error_5] |
| Log_Error_6 | [dbo].[osLog_Error_6] |
| Log_Error_7 | [dbo].[osLog_Error_7] |
| Log_Error_8 | [dbo].[osLog_Error_8] |
| Log_Error_9 | [dbo].[osLog_Error_9] |
| Log_Extension_0 | [dbo].[oslog_Extension_0] |
| Log_Extension_1 | [dbo].[oslog_Extension_1] |
| Log_Extension_2 | [dbo].[oslog_Extension_2] |
| Log_Extension_3 | [dbo].[oslog_Extension_3] |
| Log_Extension_4 | [dbo].[oslog_Extension_4] |
| Log_Extension_5 | [dbo].[oslog_Extension_5] |
| Log_Extension_6 | [dbo].[oslog_Extension_6] |
| Log_Extension_7 | [dbo].[oslog_Extension_7] |
| Log_Extension_8 | [dbo].[oslog_Extension_8] |
| Log_Extension_9 | [dbo].[oslog_Extension_9] |
| Log_General_0 | [dbo].[oslog_General_0] |
| Log_General_1 | [dbo].[oslog_General_1] |
| Log_General_2 | [dbo].[oslog_General_2] |
| Log_General_3 | [dbo].[oslog_General_3] |
| Log_General_4 | [dbo].[oslog_General_4] |
| Log_General_5 | [dbo].[oslog_General_5] |
| Log_General_6 | [dbo].[oslog_General_6] |
| Log_General_7 | [dbo].[oslog_General_7] |
| Log_General_8 | [dbo].[oslog_General_8] |
| Log_General_9 | [dbo].[oslog_General_9] |
| Log_Integration_0 | [dbo].[oslog_Integration_0] |
| Log_Integration_1 | [dbo].[oslog_Integration_1] |
| Log_Integration_2 | [dbo].[oslog_Integration_2] |
| Log_Integration_3 | [dbo].[oslog_Integration_3] |
| Log_Integration_4 | [dbo].[oslog_Integration_4] |
| Log_Integration_5 | [dbo].[oslog_Integration_5] |
| Log_Integration_6 | [dbo].[oslog_Integration_6] |
| Log_Integration_7 | [dbo].[oslog_Integration_7] |
| Log_Integration_8 | [dbo].[oslog_Integration_8] |
| Log_Integration_9 | [dbo].[oslog_Integration_9] |
| Log_Integration_Detail_0 | [dbo].[oslog_Int_Detail_0] |
| Log_Integration_Detail_1 | [dbo].[oslog_Int_Detail_1] |
| Log_Integration_Detail_2 | [dbo].[oslog_Int_Detail_2] |
| Log_Integration_Detail_3 | [dbo].[oslog_Int_Detail_3] |
| Log_Integration_Detail_4 | [dbo].[oslog_Int_Detail_4] |
| Log_Integration_Detail_5 | [dbo].[oslog_Int_Detail_5] |
| Log_Integration_Detail_6 | [dbo].[oslog_Int_Detail_6] |
| Log_Integration_Detail_7 | [dbo].[oslog_Int_Detail_7] |
| Log_Integration_Detail_8 | [dbo].[oslog_Int_Detail_8] |
| Log_Integration_Detail_9 | [dbo].[oslog_Int_Detail_9] |
| Log_Mobile_Request_0 | [dbo].[oslog_Mobile_Request_0] |
| Log_Mobile_Request_1 | [dbo].[oslog_Mobile_Request_1] |
| Log_Mobile_Request_2 | [dbo].[oslog_Mobile_Request_2] |
| Log_Mobile_Request_3 | [dbo].[oslog_Mobile_Request_3] |
| Log_Mobile_Request_4 | [dbo].[oslog_Mobile_Request_4] |
| Log_Mobile_Request_5 | [dbo].[oslog_Mobile_Request_5] |
| Log_Mobile_Request_6 | [dbo].[oslog_Mobile_Request_6] |
| Log_Mobile_Request_7 | [dbo].[oslog_Mobile_Request_7] |
| Log_Mobile_Request_8 | [dbo].[oslog_Mobile_Request_8] |
| Log_Mobile_Request_9 | [dbo].[oslog_Mobile_Request_9] |
| Log_Screen_0 | [dbo].[oslog_Screen_0] |
| Log_Screen_1 | [dbo].[oslog_Screen_1] |
| Log_Screen_2 | [dbo].[oslog_Screen_2] |
| Log_Screen_3 | [dbo].[oslog_Screen_3] |
| Log_Screen_4 | [dbo].[oslog_Screen_4] |
| Log_Screen_5 | [dbo].[oslog_Screen_5] |
| Log_Screen_6 | [dbo].[oslog_Screen_6] |
| Log_Screen_7 | [dbo].[oslog_Screen_7] |
| Log_Screen_8 | [dbo].[oslog_Screen_8] |
| Log_Screen_9 | [dbo].[oslog_Screen_9] |

# 現在どのセットを使っているかを確認する
0-9の数字を週毎でローテートして使っているので、現在どのセット（＝サイクル数）を使っているかを知らないと、確認したいログが実際どのテーブルに含まれるかがわかりません。

## ビューを経由してCYCLE列で確認
当週のビューを適当に1件取得すると、そのビューで対象としているセット（0-9の数字）がCYCLE列に含まれています。

## 仕様に基づいて計算する
[ログのローテーション](https://success.outsystems.com/ja-jp/Documentation/11/Managing_the_Applications_Lifecycle/Monitor_and_Troubleshoot/Logging_database_and_architecture/The_log_tables_and_views#.E3.83.AD.E3.82.B0.E3.81.AE.E3.83.AD.E3.83.BC.E3.83.86.E3.83.BC.E3.82.B7.E3.83.A7.E3.83.B3)に記載がありました。

> サイクル数は、現在の日付から算出されます。このために、数式<2000年1月1日から現在までの週数> MOD 10を使用します。

というわけで、計算するFunctionを作ってみましょう。
日付を指定して、その日付がどのサイクル数のログに出るかを返すFunctionです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/f23b1741-502d-5bce-03c2-75ad33670f61.png)


```
CurrentCyle = Mod(DiffDays(TextToDate("2000/1/1"), TargetDate) / 7, 10)
```

1. DiffDaysで2000/1/1から指定日までの日数を計算
2. 日数を7で割って経過週数を計算（端数切捨て）
3. Modで10で割ったあまりを算出（これがサイクル数）

# 実際にログを確認する
DBツールでDBに直接アクセスする。
確認したいログの種類と計算したサイクル数から、物理テーブルの表を確認してテーブル名を取得。
あとはGUIツールで見るか、直接SQLを発行して確認する。