# Track users’ logs with morgan

Morgan is a logging middleware used to handle the logging of your admin backend. It is called this way in your `app.js` file:

{% code title="app.js" %}

```javascript
const morgan = require('morgan')
...
app.use(morgan('tiny'))
...
```

{% endcode %}

The logs are printed in this format:

![Screenshot 2020-07-21 at 18.17.25.png](https://storage.googleapis.com/slite-api-files-production/files/c1aff565-854f-45b5-9519-53196044ea29/Screenshot%25202020-07-21%2520at%252018.17.25.png)

You can choose to have more verbose logs, add new information, and customize the log format using [morgan](https://github.com/expressjs/morgan).

You can take a look at the package documentation [here](https://www.npmjs.com/package/morgan).

{% hint style="info" %}
This can be especially useful if you store your logs and use them to track user activities.
{% endhint %}

## Add new information

You could add in your logging data like:

* user IP (IP of the request),
* user name & team from the Forest Admin token

You can adjust the code in your `app.js` file using the snippet below.

The logs printed will include information about the user IP, the user connected with Forest and his team.

{% code title="app.js" %}

```javascript
const morgan = require('morgan')
...
morgan.token('ip', (req) => req.headers['x-forwarded-for'] || req.connection.remoteAddress);
morgan.token('user', (req) => {
  if (req.user) { return req.user.email; }
  return 'no user info';
});
morgan.token('team', (req) => {
  if (req.user) { return req.user.team; }
  return '-';
});

app.use(morgan(':ip :user :team [:date[clf]] :method :url :response-time'));
...

```

{% endcode %}

This will give you the following log output:

![Screenshot 2020-07-21 at 18.17.45.png](https://storage.googleapis.com/slite-api-files-production/files/fc2dcd48-f7ed-40a4-b4a5-cf1b206506c4/Screenshot%25202020-07-21%2520at%252018.17.45.png)

## Customize the format of the logs

You can also use a custom format like a JSON to output your logs.

{% code title="app.js" %}

```javascript
const morgan = require('morgan')
...

morgan.token('ip', (req) => req.headers['x-forwarded-for'] || req.connection.remoteAddress);
morgan.token('user', (req) => {
  if (req.user) { return req.user.email; }
  return 'no user info';
});
morgan.token('team', (req) => {
  if (req.user) { return req.user.team; }
  return '-';
});

function jsonFormat(tokens, req, res) {
  return JSON.stringify({
    ip: tokens.ip(req, res),
    user: tokens.user(req, res),
    team: tokens.team(req, res),
    time: tokens.date(req, res, 'iso'),
    method: tokens.method(req, res),
    url: tokens.url(req, res),
    'http-version': tokens['http-version'](req, res),
    'status-code': tokens.status(req, res),
    'content-length': tokens.res(req, res, 'content-length'),
    referrer: tokens.referrer(req, res),
    'user-agent': tokens['user-agent'](req, res),
  });
}

app.use(morgan(jsonFormat));
...
```

{% endcode %}

This will give you the following log output:

![Screenshot 2020-07-21 at 17.58.38.png](https://storage.googleapis.com/slite-api-files-production/files/45445589-7721-4c6c-b7e2-a985514b73a2/Screenshot%25202020-07-21%2520at%252017.58.38.png)

## Store logs via a stream

You can also choose to store your logs using a stream. The following example shows how you can store your logs into a CSV file.

{% code title="app.js" %}

```javascript
const morgan = require('morgan')
...

morgan.token('ip', (req) => req.headers['x-forwarded-for'] || req.connection.remoteAddress);
morgan.token('user', (req) => {
  if (req.user) { return req.user.email; }
  return 'no user info';
});
morgan.token('team', (req) => {
  if (req.user) { return req.user.team; }
  return '-';
});

let accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.csv'), { flags: 'a' });

app.use(morgan(':ip,:user,:team,[:date[clf]],:method,:url,:response-time', { stream: accessLogStream }));
...
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestadmin.com/woodshop/how-tos/get-user-specific-activity-from-your-server-logs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
