# Logs

The default location of logs is inside the `/var/log/memgraph/` directory. That
location can be configured using the `--log-file` [configuration
flag](https://memgraph.com/docs/database-management/configuration#other).

Memgraph tracks logs at various levels: TRACE, DEBUG, INFO, WARNING, ERROR,
CRITICAL. By default, it is using the WARNING level, but you can change the
level using the [`--log-level`](https://memgraph.com/docs/database-management/configuration#other)
configuration flag or [during
runtime](https://memgraph.com/docs/database-management/configuration#change-configuration-settings-during-runtime) using the `SET
DATABASE SETTING "log.level" TO "TRACE";`

By default, Memgraph uses synchronous logging. To reduce the performance impact
of logging on query execution, you can enable asynchronous logging by setting the
[`--logger-type`](https://memgraph.com/docs/database-management/configuration#other) configuration flag
to `async`. With asynchronous logging, log messages are buffered and written in a
background thread instead of blocking the executing thread.

Memgraph creates daily log files and retains them for 35 days by default. You
can change the retention period using the
[`--log-retention-days`](https://memgraph.com/docs/database-management/configuration#other) configuration
flag.

The configuration set during runtime will be applied only for that session.

You can check the log level by running `SHOW DATABASE SETTING "log.level";` query.

To access the logs from the Memgraph Lab interface, make sure to expose the port
7444 when starting Memgraph with Docker. 


> **Info**
>
> To get additional information on the generated query plans, set
> `--debug-query-plans` to `True`, along with `--log-level` set to `DEBUG` or `TRACE`.


## RocksDB info logs

Besides its own log file, Memgraph also produces the info logs written by the
embedded RocksDB instances. These are separate from `--log-file` and live next
to the data of each RocksDB instance inside the [data
directory](https://memgraph.com/docs/database-management/configuration#other), as a live `LOG` file and
rolled `LOG.old.<timestamp>` files.

Memgraph opens a RocksDB instance for the key-value stores holding
authentication data, triggers, streams, settings and replication or high
availability state, and one more for the `ON_DISK_TRANSACTIONAL` storage mode.
Two flags control the info logs of all of them:

| Flag | Description |
|------|-------------|
| [`--storage-rocksdb-info-log-level=INFO_LEVEL`](https://memgraph.com/docs/database-management/configuration#storage) | Verbosity of the info logs. Allowed values: `DEBUG_LEVEL`, `INFO_LEVEL`, `WARN_LEVEL`, `ERROR_LEVEL`, `FATAL_LEVEL`, `HEADER_LEVEL`. |
| [`--storage-rocksdb-keep-log-file-num=1000`](https://memgraph.com/docs/database-management/configuration#storage) | Maximum number of info log files kept per RocksDB instance. |

Every Memgraph restart rolls the current info log into a new file, so an
instance that restarts often accumulates up to
`--storage-rocksdb-keep-log-file-num` files per RocksDB instance before the
oldest ones start being deleted. On deployments with constrained disk space,
lower the flag from its default of `1000`.

## Slow and failed query logging

Memgraph can emit two operational log streams to the main log, useful for
spotting latency outliers and errors without enabling full [session
trace](https://memgraph.com/docs/database-management/monitoring#session-trace):

- `[slow-query]` at `WARNING` level — one line per successful query whose
  end-to-end time reaches a configurable threshold, optionally followed by its
  EXPLAIN plan.
- `[failed-query]` at `ERROR` level — one line per query that throws.

Both streams are off by default (except that the plan is appended once
slow-query logging is enabled) and are controlled by these flags:

| Flag                       | Setting name          | Description                                                                                                              | Type      |
| -------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | --------- |
| `--log-min-duration-ms=-1` | `log.min_duration_ms` | Log successful queries whose `parse + plan + execute` time (ms) reaches this threshold. `-1` disables; `0` logs every successful query; `>0` is the threshold in milliseconds. | `[int64]` |
| `--log-failed-queries=false` | `log.failed_queries` | Log each failed query.                                                                                                   | `[bool]`  |
| `--log-query-plan=true`    | `log.query_plan`      | Append the query's EXPLAIN plan to its `[slow-query]` line.                                                              | `[bool]`  |

The reported duration is the sum of parsing, planning and execution time; the
commit phase and `AFTER COMMIT` triggers are excluded.

### Line format

```plaintext
[slow-query] duration_ms= user=<user> db=<db> query="<query>"
PLAN:
  <indented EXPLAIN plan, only when log.query_plan is true>
[failed-query] user=<user> db=<db> error="<message>" query="<query>"
```

The `query=` and `error=` fields are quoted and self-delimiting: `"` and `\`
are escaped, and newlines, carriage returns and tabs become `\n`, `\r` and `\t`
so a record never spans multiple log lines. Only the slow-query `PLAN:` block
is intentionally multi-line. `user=` is empty for unauthenticated sessions, and
`db=<none>` is shown when no database is selected.


> **Info**
>
> DDL queries (`CREATE INDEX`, `DROP INDEX`, constraints, etc.) do not populate
> execution time, so a long index build reports only parse and plan time and is
> effectively never picked up as slow. The slow-query logger targets the
> read/write Cypher workload, not schema-maintenance operations.


### Configuring at runtime and per session

The three settings can be changed globally at runtime and persist between runs:

```cypher
SET DATABASE SETTING "log.min_duration_ms" TO "500";
```

They can also be overridden for the current session only, which takes
precedence over the global value:

```cypher
SET SESSION SETTING "log.min_duration_ms" TO "500";
RESET SESSION SETTING "log.min_duration_ms";
```

`SET SESSION SETTING` accepts only the three keys above; any other key raises
`Setting "<key>" cannot be set per-session`.

## Access logs

If you installed Memgraph with Linux, logs can be found in the
`/var/log/memgraph` directory.

If you installed Memgraph using Docker, the easiest way to access the logs is by
having a [named volume](https://docs.docker.com/storage/volumes/) on the
`/var/log/memgraph` directory and checking its content. If you're not using a
named volume, here are the steps to access the logs within the running Docker
container:


### Find container ID
Open a new terminal and find the `CONTAINER_ID` of the Memgraph Docker
    container:

    ```plaintext
    docker ps
    ```
### Enter the container
Run the following command:

    ```plaintext
    docker exec -it <CONTAINER_ID> bash
    ```

    Replace the `<CONTAINER_ID>` parameter with the correct value.
### List the contents of the `/var/log/memgraph` directory
```plaintext
    ls /var/log/memgraph
    ```
### List the content of the log
To list the content of the log, use the `cat /var/log/memgraph/<memgraph_date>.log` command.

    For example, if the `ls` command returned `memgraph_2025-02-05.log` you would
    list the contents using the following command:

    ```plaintext
    cat /var/log/memgraph/memgraph_2025-02-05.log
    ```
    **Filtering unnecessary log messages**

    When you inspect Memgraph's log files, you might find too many details that make it
    hard to spot the important messages. To make analyzing the logs easier, you can
    use a tool such as `grep` to remove the messages you don't need. 
    
    For instance, if you want to ignore messages about internal Memgraph Lab work, run the following command:

    ```bash
    grep -v '{source:"lab-system"}' /var/log/memgraph_2025-02-05.log
    ```

    Every query executed by Memgraph Lab has `{source:"lab-system"}` metadata attached to it. 
    Therefore, the above command will exclude the log lines containing any query executed by Memgraph Lab. 

    If you want to avoid having too much information storage, indexes, rules and triggers you can run the following command:

    ```bash
    grep -v -E "SHOW STORAGE INFO|SHOW INDEX INFO|SHOW CONSTRAINT INFO|SHOW TRIGGERS" /var/log/memgraph_2025-02-05.log
    ```

    The above command excludes log lines containing `SHOW STORAGE INFO`, `SHOW INDEX INFO`, `SHOW CONSTRAINT INFO` and `SHOW
    TRIGGERS`, making it easier to focus on the messages that are most relevant to
    your monitoring and troubleshooting efforts.

    
> **Info**
>
> Replace `memgraph_2025-02-05.log` from `/var/log/memgraph/memgraph_2025-02-05.log` with the actual log file name.

### Save logs locally
If you want to save the log to your computer, exit the container with
    `CTRL+D` or `exit`, place yourself in a directory where you want to save the copy and run
    the following command:

    ```plaintext
    docker cp  <CONTAINER_ID>:/var/log/memgraph/<memgraph_date>.log <memgraph_date>.log
    ```

    For example, the following command will make a copy of the
    `memgraph_2025-02-05.log` file on the user's desktop:

    ```plaintext
    C:\Users\Vlasta\Desktop>docker cp bb3de2634afe:/var/log/memgraph/memgraph_2025-02-05.log memgraph_2025-02-05.log

    ```



## Hiding passwords (Enterprise)

To enhance security, it's crucial to ensure that sensitive information is not logged.
In the example below we can see how passwords are masked in the Enterprise edition of Memgraph:

Original log (Community version):

```plaintext
SET PASSWORD TO 'newpassword' REPLACE 'oldpassword'
```

Masked log (Enterprise version):

```plaintext
SET PASSWORD TO '****' REPLACE '****'
```

All passwords are replaced with `****` to prevent their exposure in the logs. 
This approach ensures that even if logs are accessed by unauthorized individuals, 
they won't be able to retrieve the actual passwords.

## Audit log (Enterprise)

Memgraph supports all query audit logging. When enabled, the audit log contains
records of all queries executed on the database.  Each executed query is one
entry (one line) in the audit log. The audit log itself is a CSV file.

All audit logs are written to
`<MEMGRAPH_DURABILITY_DIRECTORY>/audit/audit.log`.  The log is rotated using
`logrotate`, so entries in the `audit.log` file are always the newest entries.
Entries in `audit.log.1`, `audit.log.2.gz`, etc.  are older entries. The
default log rotation configuration can be found in `/etc/logrotate.d/memgraph`.
By default, the log is rotated every day and a full year of entries is
preserved. You can modify the values to your own needs and preferences.

### Format

The audit log contains the following information formatted into a CSV file:
```plaintext
<timestamp>,<address>,<username>,<query>,<params>
```
For each query, the supplied query parameters are also logged. The query is
escaped and quoted so that commas in queries don't affect the correctness of
the CSV. The parameters are encoded as JSON objects and are then escaped and
quoted.

### Example

This is an example of the audit log:

```plaintext
1551376833.225395,127.0.0.1,admin,"MATCH (n) DETACH DELETE n","{}"
1551376833.257825,127.0.0.1,admin,"CREATE (n {name: $name})","{\"name\":\"alice\"}"
1551376833.273546,127.0.0.1,admin,"MATCH (n), (m) CREATE (n)-[:e {when: $when}]->(m)","{\"when\":42}"
1551376833.300955,127.0.0.1,admin,"MATCH (n), (m) SET n.value = m.value","{}"
```

We can see that all of the queries were executed from the loopback address and
were executed by the user `admin`.  The executed queries are:

```
 Query                                            | Parameters
--------------------------------------------------|-----------
MATCH (n) DETACH DELETE n                         | {}
CREATE (n {name: $name})                          | {"name": "alice"}
MATCH (n), (m) CREATE (n)-[:e {when: $when}]->(m) | {"when": 42}
MATCH (n), (m) SET n.value = m.value              | {}
```

### Parsing the log

If you wish to parse the log, the following Python snippet shows how to extract
data from the audit log:

```python
import csv
import json

with open("audit.log") as f:
    reader = csv.reader(f, delimiter=',', doublequote=False,
                        escapechar='\\', lineterminator='\n',
                        quotechar='"', quoting=csv.QUOTE_MINIMAL,
                        skipinitialspace=False, strict=True)
    for line in reader:
        timestamp, address, username, query, params = line
        params = json.loads(params)
        # Rest of your code that processes the logs.
```

### Flags

Use the following flags to configure audit logging in Memgraph.

| Flag                               | Description                                                                                    |
|------------------------------------|------------------------------------------------------------------------------------------------|
| `--audit-enabled`                  | Enables audit logging.                                                                         |
| `--audit-buffer-size`              | Controls the in-memory buffer size used for audit logs.                                        |
| `--audit-buffer-flush-interval-ms` | Controls the time interval (in milliseconds) used for flushing the in-memory buffer to disk.   |
