
## Asset search logs

URL: https://docs.atlan.com/product/capabilities/build-apps/sdks/python/how-tos/review-access-logs

> Track asset view activity in Atlan using SearchLogRequest and the Python SDK — POST /api/meta/search/searchlog returns viewer counts, most-viewed assets, and detailed log entries per asset.

# SearchLogRequest: view or review asset access logs

Use `SearchLogRequest` in the Atlan Python SDK to programmatically view or review asset access logs.

Search logs provide valuable insights for analysts to monitor the popularity of assets within Atlan, including details such as the most visited assets, user interactions, and emerging search patterns. Accessing the search log of an asset is a flexible operation, which may seem more intricate compared to other operations. To harness the complete flexibility of Atlan's search, the SDK introduces a dedicated `SearchLogRequest` object.

:::warning[Similar but not identical to searching in general]
Atlan's search log, which contains the search logs of an asset, utilizes Elasticsearch. This makes the approach to accessing search logs similar to [searching](https://docs.atlan.com/llms/platform/python/references/llms.txt). However, there are differences, as the search log uses a distinct index from the broader search. If you're feeling adventurous, feel free to experiment with the more complex search mechanisms outlined in the [searching](https://docs.atlan.com/llms/platform/python/references/llms.txt) section. Nevertheless, this should be sufficient to help you get started with accessing asset search logs.
:::

## Most recent viewers of asset

To retrieve the most recent viewers of an asset:

### Java

```java showLineNumbers title="Retrieve the most recent viewers of an asset"
List viewers = SearchLog.mostRecentViewers( // (1)
 client, "955c455d-cfea-4c9c-844d-e226edf8b6da", 20, List.of("atlansupport")
);

for (UserViews viewer: viewers)
```

1. You must provide `GUID` of the asset and specify the **maximum number of recent users** to be considered for the search log request.

 - Optionally, you may provide a list of usernames to be excluded from the search log results.

 Because this operation will directly look up the asset's views in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

2. You can then iterate through each recent viewers.
3. Name of the user who viewed the asset.
4. Number of times the user viewed the asset.
5. When the user most recently viewed the asset (epoch-style), in milliseconds.

### Python

```python showLineNumbers title="Retrieve the most recent viewers of an asset"

from pyatlan.client.atlan import AtlanClient
from pyatlan.model.search_log import SearchLogRequest

client = AtlanClient()

request = SearchLogRequest.most_recent_viewers( # (1)
 guid="955c455d-cfea-4c9c-844d-e226edf8b6da",
 max_users=20,
 exclude_users=["atlansupport"],
)
response = client.search_log.search(request)

for viewer in response.user_views: # (2)
 user = viewer.username # (3)
 view_count = viewer.view_count # (4)
 last_accessed = viewer.most_recent_view # (5)
```

1. You must provide a `GUID` and specify the
**maximum number of recent users** to be considered for the search log request.
 - Optionally, you may provide a list of usernames
 to be excluded from the search log results.
2. You can then iterate through each recent viewers.
3. Name of the user who viewed the asset.
4. Number of times the user viewed the asset.
5. When the user most recently viewed the asset (epoch-style), in milliseconds.

### Kotlin

```kotlin showLineNumbers title="Retrieve the most recent viewers of an asset"
val viewers = SearchLog.mostRecentViewers( // (1)
 client, "955c455d-cfea-4c9c-844d-e226edf8b6da", maxUsers=20, listOf("atlansupport")
)

for (viewer in viewers)
```

1. You must provide a `GUID` and specify the **maximum number of recent users** to be considered for the search log request.

 - Optionally, you may provide a list of usernames to be excluded from the search log results.

 Because this operation will directly look up the asset's views in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

2. You can then iterate through each recent viewers.
3. Name of the user who viewed the asset.
4. Number of times the user viewed the asset.
5. When the user most recently viewed the asset (epoch-style), in milliseconds.

### Raw REST API

```json showLineNumbers title="POST /api/meta/search/searchlog"
{
 "dsl": {
 "from": 0,
 "size": 0,
 "aggregations": {
 "uniqueUsers": {
 "aggregations": {
 "latestTimestamp": {
 "max": {
 "field": "timestamp"
 }
 }
 },
 "terms": {
 "field": "userName",
 "order": [
 {
 "latestTimestamp": "desc"
 }
 ],
 "size": 20 // (2)
 }
 },
 "totalDistinctUsers": {
 "cardinality": {
 "field": "userName",
 "precision_threshold": 1000
 }
 }
 },
 "query": {
 "bool": {
 "must_not": [
 {
 "terms": {
 "userName": [
 "atlansupport"
 ] // (3)
 }
 }
 ],
 "filter": [
 {
 "term": {
 "utmTags": {
 "value": "action_asset_viewed"
 }
 }
 },
 {
 "term": {
 "entityGuidsAll": {
 "value": "955c455d-cfea-4c9c-844d-e226edf8b6da", // (1)
 "case_insensitive": false
 }
 }
 },
 {
 "bool": {
 "minimum_should_match": 1,
 "should": [
 {
 "term": {
 "utmTags": {
 "value": "ui_profile"
 }
 }
 },
 {
 "term": {
 "utmTags": {
 "value": "ui_sidebar"
 }
 }
 }
 ]
 }
 }
 ]
 }
 },
 "sort": [
 {
 "timestamp": {
 "order": "asc"
 }
 }
 ],
 "track_total_hits": true
 }
}
```

1. `GUID` of the asset for which you are seeking the details of recent viewers.
2. **Maximum number of recent users** to be considered for the search log request.
3. Optionally, you may provide a list of usernames to be excluded from the search log results.

## Most viewed assets

To retrieve the most viewed assets by its total views:

### Java

```java showLineNumbers title="Retrieve the most viewed assets by its total views"

List topAssetsByViews = SearchLog.mostViewedAssets(
 client, 10, false, List.of("atlansupport") // (1)
);

for (AssetViews detail: topAssetsByViews)
```

1. To retrieve the most viewed assets, specify the maximum number of assets you want to retrieve. Then specify whether you want the most-viewed based on total number of views, irrespective of distinct users (`false`); or based on the most distinct users, irrespective of total views (`true`).

 - Optionally, you may provide a list of usernames to be excluded from the search log results.

 Because this operation will directly look up the asset's views in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

2. You can then iterate through each asset's views.
3. `GUID` of the asset that was viewed.
4. Number of times the asset has been viewed (in total).
5. Number of distinct users that have viewed the asset.

### Python

```python showLineNumbers title="Retrieve the most viewed assets by its total view"

from pyatlan.client.atlan import AtlanClient
from pyatlan.model.search_log import SearchLogRequest

client = AtlanClient()

request = SearchLogRequest.most_viewed_assets( # (1)
 max_assets=10,
 by_different_user=False,
 exclude_users=["username"],
)
response = client.search_log.search(request)

for detail in response.asset_views: # (2)
 guid = detail.guid # (3)
 total_views = detail.total_views # (4)
 distinct_users = detail.distinct_users # (5)
```

1. To retrieve the most viewed assets, specify the maximum number of assets you want to retrieve.
Then specify whether you want the most-viewed based on total number of views, irrespective
of distinct users (`False`); or based on the most distinct users, irrespective of total views (`True`).
 - Optionally, you may provide a list of usernames
 to be excluded from the search log results.
2. You can then iterate through each asset's viewers.
3. Name of the user who viewed the asset.
4. Number of times the user viewed the asset.
5. Number of distinct users that have viewed the asset.

### Kotlin

```kotlin showLineNumbers title="Retrieve the most viewed assets by its total view"
val topAssetsByViews = SearchLog.mostViewedAssets(
 10, byDifferentUsers=false, excludeUsers=listOf("atlansupport")
) // (1)

for (detail in topAssetsByViews)
```

1. To retrieve the most viewed assets, specify the maximum number of assets you want to retrieve. Then specify whether you want the most-viewed based on total number of views, irrespective of distinct users (`false`); or based on the most distinct users, irrespective of total views (`true`).

 - Optionally, you may provide a list of usernames to be excluded from the search log results.

 Because this operation will directly look up the asset's views in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

2. You can then iterate through each asset's viewers.
3. Name of the user who viewed the asset.
4. Number of times the user viewed the asset.
5. Number of distinct users that have viewed the asset.

### Raw REST API

```json showLineNumbers title="POST /api/meta/search/searchlog"
{
 "dsl": {
 "from": 0,
 "size": 0,
 "aggregations": {
 "uniqueAssets": {
 "aggregations": {
 "uniqueUsers": {
 "cardinality": {
 "field": "userName",
 "precision_threshold": 1000
 }
 }
 },
 "terms": {
 "field": "entityGuidsAll",
 "size": 10 // (1)
 // (2)
 }
 },
 "totalDistinctUsers": {
 "cardinality": {
 "field": "userName",
 "precision_threshold": 1000
 }
 }
 },
 "query": {
 "bool": {
 "must_not": [
 {
 "terms": {
 "userName": [
 "atlansupport"
 ] // (3)
 }
 }
 ],
 "filter": [
 {
 "term": {
 "utmTags": {
 "value": "action_asset_viewed"
 }
 }
 },
 {
 "bool": {
 "minimum_should_match": 1,
 "should": [
 {
 "term": {
 "utmTags": {
 "value": "ui_profile"
 }
 }
 },
 {
 "term": {
 "utmTags": {
 "value": "ui_sidebar"
 }
 }
 }
 ]
 }
 }
 ]
 }
 },
 "sort": [
 {
 "timestamp": {
 "order": "asc"
 }
 }
 ],
 "track_total_hits": true
 }
}
```

1. **Maximum number of assets** to be considered for the search log request
2. If you want to retrieve most viewed assets based on the most distinct users,
regardless of total views, include `"order": [{"uniqueUsers": "desc"}]` here.
3. Optionally, you may provide a list of usernames to be excluded from the search log results.

## Detailed search log entries

To retrieve detailed search log entries (paged via lazy fetching):

### Java

```java showLineNumbers title="To retrieve detailed search log entries"

SearchLog.viewsByGuid(
 client,
 "955c455d-cfea-4c9c-844d-e226edf8b6da",
 List.of("atlansupport")
 ) // (1)
 .stream() // (2)
 .limit(100) // (3)
 .forEach(entry -> { // (4)
 logger.info(entry.getUserName() + " from " + entry.getIpAddress());
 });
```

1. You must provide the `GUID` of the asset for which you are seeking the detailed search log entries.

 - Optionally, you may provide a list of usernames to be excluded from the search log results.

 Because this operation will directly look up the asset's views in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

2. The search will only run when you call the `stream()` method,
which will then lazily-load each page of results into a stream
3. With streaming, you can apply your own limits to the maximum number of results you want to process.

 :::tip[Independent of page size]
Note that this is independent of page size. You could page through results 50 at a time, but only process a maximum of 100 total results this way. Since the results are lazily-loaded when streaming, only the first two pages of results would be retrieved in such a scenario.
 :::
4. You can then iterate through each `log entry` to retrieve details
such as the **username** and **IP address** of the search logs.

### Python

```python showLineNumbers title="To retrieve detailed search log entries"

from pyatlan.client.atlan import AtlanClient
from pyatlan.model.search_log import SearchLogRequest

client = AtlanClient()

request = SearchLogRequest.views_by_guid( # (1)
 guid="955c455d-cfea-4c9c-844d-e226edf8b6da",
 size=20,
 exclude_users=["atlansupport"],
)

response = client.search_log.search(criteria=request, bulk=False) # (2)

for entry in response: # (3)
 LOGGER.info(f"{entry.user_name} from {entry.ip_address}")
```

1. You must provide the `GUID` of the asset and specify
the **maximum number of log entries per page** for the search log request.
 - Optionally, you may provide a list of usernames
 to be excluded from the search log results.
2. `client.search_log.search()` method takes following parameters:

 - `criteria`: defines the search query to execute the search.
 - `bulk`(**default: False**): specifies whether to execute the search in bulk mode for retrieving the search logs matching the criteria. This mode is optimized for handling large results (more than `10,000`). When enabled (`True`), the results will be reordered based on the creation timestamp to facilitate iterating through large datasets.

 :::note
If the number of results exceeds the predefined threshold
(`10,000` assets) search log search will be automatically converted into a `bulk` search.
 :::
3. You can then iterate through each `log entry` to
retrieve details such as the **username** and **IP address** of the search logs.

### Kotlin

```kotlin showLineNumbers title="To retrieve detailed search log entries"

 SearchLog.viewsByGuid(
 client,
 "955c455d-cfea-4c9c-844d-e226edf8b6da",
 listOf("atlansupport")
 ) // (1)
 .stream() // (2)
 .limit(100) // (3)
 .forEach { entry -> // (4)
 logger.info { "${entry.userName} from ${entry.ipAddress}" }
 }
```

1. You must provide the `GUID` of the asset for which you are seeking the detailed search log entries.

 - Optionally, you may provide a list of usernames to be excluded from the search log results.

 Because this operation will directly look up the asset's views in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

2. The search will only run when you call the `stream()` method,
which will then lazily-load each page of results into a stream
3. With streaming, you can apply your own limits to the maximum number of results you want to process.

 :::tip[Independent of page size]
Note that this is independent of page size. You could page through results 50 at a time, but only process a maximum of 100 total results this way. Since the results are lazily-loaded when streaming, only the first two pages of results would be retrieved in such a scenario.
 :::
4. You can then iterate through each log entry to retrieve details
such as the **username** and **IP address** of the search logs.

### Raw REST API

```json showLineNumbers title="POST /api/meta/search/searchlog"

{
 "dsl": {
 "from": 0,
 "size": 100, // (1)
 "query": {
 "bool": {
 "must_not": [
 {
 "terms": {
 "userName": [
 "atlansupport"
 ] // (3)
 }
 }
 ],
 "filter": [
 {
 "term": {
 "utmTags": {
 "value": "action_asset_viewed"
 }
 }
 },
 {
 "term": {
 "entityGuidsAll": {
 "value": "955c455d-cfea-4c9c-844d-e226edf8b6da", // (2)
 "case_insensitive": false
 }
 }
 },
 {
 "bool": {
 "minimum_should_match": 1,
 "should": [
 {
 "term": {
 "utmTags": {
 "value": "ui_profile"
 }
 }
 },
 {
 "term": {
 "utmTags": {
 "value": "ui_sidebar"
 }
 }
 }
 ]
 }
 }
 ]
 }
 },
 "sort": [
 {
 "timestamp": {
 "order": "asc"
 }
 }
 ],
 "track_total_hits": true
 }
}
```

1. Page size of the search log request.
2. `GUID` of the asset for which you are seeking the detailed search log entries.
3. Optionally, you may provide a list of usernames to be excluded from the search log results.

---
