Access Logs with the Admin API
Overview
You can request an application's logs programmatically by accessing the logging endpoints of the Realm Admin API.
The examples in this section use the following helper functions in a Function:
async function authenticate(publicApiKey, privateApiKey) { const result = await context.http.post({ url: `${ADMIN_API_BASE_URL}/auth/providers/mongodb-cloud/login`, headers: { "Content-Type": ["application/json"], "Accept": ["application/json"], }, body: { "username": publicApiKey, "apiKey": privateApiKey, }, encodeBodyAsJSON: true }) return EJSON.parse(result.body.text()); } function formatQueryString(queryParams) { const params = Object.entries(queryParams); return params.length > 0 ? "?" + params.map(([a, b]) => `${a}=${b}`).join("&") : "" }
Application ID
In order to request your application's log entries, you'll need the application's object ID. You can find your application ID in the URL when you are accessing your Realm app through cloud.mongodb.com. You can also get the application ID via curl.
When you access your Realm app, you should have a URL of the following format:
https://realm.mongodb.com/groups/<Atlas Organization ID>/apps/<Realm App ID>/dashboard
You will use the Realm App ID in the URL to call the logging endpoints.
Get Recent Logs
To return the 100 most recent log entries for your application, call the Logging endpoint with no additional parameters:
const ADMIN_API_BASE_URL = "https://realm.mongodb.com/api/admin/v3.0"; exports = async function() { // Get values that you need for requests const projectId = "<Atlas Project ID>"; const appId = "<Realm App ID>"; const publicApiKey = "<Atlas Public API Key>"; const privateApiKey = "<Atlas Private API Key>"; // Authenticate with the Atlas API Key const { access_token } = await authenticate(publicApiKey, privateApiKey); // Get logs for your Realm App const logsEndpoint = `${ADMIN_API_BASE_URL}/groups/${projectId}/apps/${appId}/logs`; const request = { "url": logsEndpoint, "headers": { "Authorization": [`Bearer ${access_token}`] } }; const result = await context.http.get(request); const logs = EJSON.parse(result.body.text()); return logs; }
Get Logs for a Date Range
To return log entries for a specific date range, call the Logging
endpoint with either or both of the start_date
and end_date
fields:
If the date range that you specify includes more than 100 log entries, you will need to run paginated queries to access all of the entries.
const ADMIN_API_BASE_URL = "https://realm.mongodb.com/api/admin/v3.0"; exports = async function() { // Get values that you need for requests const projectId = "<Atlas Project ID>"; const appId = "<Realm App ID>"; const publicApiKey = "<Atlas Public API Key>"; const privateApiKey = "<Atlas Private API Key>"; // Authenticate with the Atlas API Key const { access_token } = await authenticate(publicApiKey, privateApiKey); // Get logs for your Realm App const logsEndpoint = `${ADMIN_API_BASE_URL}/groups/${projectId}/apps/${appId}/logs`; const request = { "url": logsEndpoint + formatQueryString({ start_date: "2019-07-01", end_date: "2019-07-31", }), "headers": { "Authorization": [`Bearer ${access_token}`] } }; const result = await context.http.get(request); const logs = EJSON.parse(result.body.text()); return logs; }
Get Paginated Logs
MongoDB Realm returns a maximum of 100 log entries for each request. If a query matches more than 100 log entries, the API returns the first "page" of 100 results and include additional parameters in the response that you can provide to get the next page(s) of up to 100 entries.
A paginated response resembles the following document, where
nextEndDate
and nextSkip
are optional:
{ logs: [<Log Entry>, ...], nextEndDate: "<End date of the next page>", nextSkip: <Offset of the next page>, }
const ADMIN_API_BASE_URL = "https://realm.mongodb.com/api/admin/v3.0"; exports = async function() { // Get values that you need for requests const projectId = "<Atlas Project ID>"; const appId = "<Realm App ID>"; const publicApiKey = "<Atlas Public API Key>"; const privateApiKey = "<Atlas Private API Key>"; // Authenticate with the Atlas API Key const { access_token } = await authenticate(publicApiKey, privateApiKey); // Get logs for your Realm App const pager = new LogPager(projectId, appId, access_token); const firstPage = await pager.getNextPage(); const secondPage = await pager.getNextPage(firstPage); const thirdPage = await pager.getNextPage(secondPage); const allLogs = await pager.getAllLogs(); } class LogPager { constructor(projectId, appId, access_token, queryParams={}) { this.logsEndpoint = `${ADMIN_API_BASE_URL}/groups/${projectId}/apps/${appId}/logs`; this.queryParams = queryParams; this.authHeaders = { Authorization: [`Bearer ${access_token}`] } } async getNextPage(prevPage) { const { nextEndDate, nextSkip } = prevPage || {}; if(prevPage && !nextEndDate) { throw new Error("Paginated API does not have any more pages.") } const request = { "headers": this.authHeaders, "url": this.logsEndpoint + formatQueryString({ ...this.queryParams, end_date: nextEndDate, skip: nextSkip, }), } const result = await context.http.get(request); const nextPage = EJSON.parse(result.body.text()); return nextPage } async getAllLogs() { // Note: If your query parameters match too many logs this might time out let logs = [] let hasNext = true; let prevPage = null while(hasNext) { const page = await getNextPage(prevPage); logs = logs.concat(page.logs); hasNext = page.nextEndDate prevPage = page } return logs; } }