Navigation

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.

Example

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:

Result Pagination

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.

Paginated Responses

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);
  console.log("First page", await pager.getNextPage());
  console.log("Second page", await pager.getNextPage(firstPage));
  console.log("All logs", 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;
  }
}