GithubHelp home page GithubHelp logo

vishalanandl177 / drf-api-logger Goto Github PK

View Code? Open in Web Editor NEW
302.0 8.0 56.0 593 KB

An API Logger for your Django Rest Framework project.

Home Page: https://github.com/vishalanandl177/DRF-API-Logger

License: Apache License 2.0

Python 91.92% HTML 8.08%
django-rest-framework logger logger-signals python python3

drf-api-logger's Introduction

DRF API Logger

version Downloads Downloads Open Source Donate

Join Community Badge Join Instagram GitHub

An API Logger for your Django Rest Framework project.

It logs all the API information for content type "application/json".

  1. URL
  2. Request Body
  3. Request Headers
  4. Request Method
  5. API Response
  6. Status Code
  7. API Call Time
  8. Server Execution Time
  9. Client IP Address

You can log API information into the database or listen to the logger signals for different use cases, or you can do both.

  • The logger uses a separate thread to run, so it won't affect your API response time.

Installation

Install or add drf-api-logger.

pip install drf-api-logger

Add in INSTALLED_APPS

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'drf_api_logger',  #  Add here
]

Add in MIDDLEWARE

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    'drf_api_logger.middleware.api_logger_middleware.APILoggerMiddleware', # Add here
]

* Add these lines in the Django Rest Framework settings file.

Store logs into the database

Log every request into the database.

DRF_API_LOGGER_DATABASE = True  # Default to False
  • Logs will be available in the Django Admin Panel.

  • The search bar will search in Request Body, Response, Headers, and API URL.

  • You can also filter the logs based on the "added_on" date, Status Code, and Request Methods.

Alt text

Alt text

Alt text

Alt text

Note: Make sure to migrate. It will create a table for the logger if "DRF_API_LOGGER_DATABASE" is True else if already exists, it will delete the table.

To listen for the logger signals.

Listen to the signal as soon as any API is called. So you can log the API data into a file or for different use cases.

DRF_API_LOGGER_SIGNAL = True  # Default to False

Example code to listen to the API Logger Signal.

"""
Import API_LOGGER_SIGNAL
"""
from drf_api_logger import API_LOGGER_SIGNAL


"""
Create a function that is going to listen to the API logger signals.
"""
def listener_one(**kwargs):
    print(kwargs)

def listener_two(**kwargs):
    print(kwargs)

"""
It will listen to all the API logs whenever an API is called.
You can also listen to signals in multiple functions.
"""
API_LOGGER_SIGNAL.listen += listener_one
API_LOGGER_SIGNAL.listen += listener_two

"""
Unsubscribe to signals.
"""

API_LOGGER_SIGNAL.listen -= listener_one

Queue

DRF API Logger usage queue to hold the logs before inserting them into the database. Once the queue is full, it bulk inserts into the database.

Specify the queue size.

DRF_LOGGER_QUEUE_MAX_SIZE = 50  # Default to 50 if not specified.

Interval

DRF API Logger also waits for a period of time. If the queue is not full and there are some logs to be inserted, it inserts after the interval ends.

Specify an interval (In Seconds).

DRF_LOGGER_INTERVAL = 10  # In Seconds, Default to 10 seconds if not specified.

Note: The API call time (added_on) is a timezone-aware datetime object. It is the actual time of the API call irrespective of interval value or queue size.

Skip namespace

You can skip the entire app to be logged into the database by specifying the namespace of the app as a list.

DRF_API_LOGGER_SKIP_NAMESPACE = ['APP_NAMESPACE1', 'APP_NAMESPACE2']

Skip URL Name

You can also skip any API to be logged by using the url_name of the API.

DRF_API_LOGGER_SKIP_URL_NAME = ['url_name1', 'url_name2']

Note: It does not log Django Admin Panel API calls.

Hide Sensitive Data From Logs

You may wish to hide sensitive information from being exposed in the logs. You do this by setting DRF_API_LOGGER_EXCLUDE_KEYS in settings.py to a list of your desired sensitive keys. The default is

DRF_API_LOGGER_EXCLUDE_KEYS = ['password', 'token', 'access', 'refresh']
# Sensitive data will be replaced with "***FILTERED***".

Change the default database to store API logs

DRF_API_LOGGER_DEFAULT_DATABASE = 'default'  # Default to "default" if not specified
"""
Make sure to migrate the database specified in DRF_API_LOGGER_DEFAULT_DATABASE.
"""

Want to identify slow APIs? (Optional)

You can also identify slow APIs by specifying DRF_API_LOGGER_SLOW_API_ABOVE in settings.py.

A new filter (By API Performance) will be visible, and you can choose a slow or fast API.

DRF_API_LOGGER_SLOW_API_ABOVE = 200  # Default to None
# Specify in milli-seconds.

Want to log only selected request methods? (Optional)

You can log only selected methods by specifying DRF_API_LOGGER_METHODS in settings.py.

DRF_API_LOGGER_METHODS = ['GET', 'POST', 'DELETE', 'PUT']  # Default to an empty list (Log all the requests).

Want to log only selected response status codes? (Optional)

You can log only selected responses by specifying DRF_API_LOGGER_STATUS_CODES in settings.py.

DRF_API_LOGGER_STATUS_CODES = [200, 400, 404, 500]  # Default to an empty list (Log all responses).

Want to log custom content types? (Optional)

You can log custom content types by specifying DRF_API_LOGGER_CONTENT_TYPES in settings.py. The specified content types will be added alongside with default content types.

DRF_API_LOGGER_CONTENT_TYPES = [
    "application/json",
    "application/vnd.api+json",
    "application/gzip",
    "application/octet-stream",
]  # Default content types.

Want to see the API information in the local timezone? (Optional)

You can also change the timezone by specifying DRF_API_LOGGER_TIMEDELTA in settings.py. It won't change the Database timezone. It will remain UTC or the timezone you have defined.

DRF_API_LOGGER_TIMEDELTA = 330 # UTC + 330 Minutes = IST (5:Hours, 30:Minutes ahead from UTC) 
# Specify in minutes.
# You can specify negative values for the countries behind the UTC timezone.
DRF_API_LOGGER_TIMEDELTA = -30  # Example

Ignore data based on maximum request or response body? (Optional)

Request/Response bodies By default, DRF API LOGGER will save the request and response bodies for each request for future viewing no matter how large. If DRF API LOGGER is used in production under heavy volume with large bodies this can have a huge impact on space/time performance.

This behavior can be configured with the following options additional:

# DRF API LOGGER takes anything < 0 as no limit.
# If response body > 1024 bytes, ignore.
DRF_API_LOGGER_MAX_REQUEST_BODY_SIZE = 1024  # default to -1, no limit.
DRF_API_LOGGER_MAX_RESPONSE_BODY_SIZE = 1024  # default to -1, no limit.

Tracing

You can enable tracing by specifying DRF_API_LOGGER_ENABLE_TRACING in settings.py. This will add a tracing ID (UUID.uuid4()) in the signals of the DRF API Logger (if enabled).

In views, you can use request.tracing_id to get the tracing ID.

DRF_API_LOGGER_ENABLE_TRACING = True  # default to False

Want to generate your tracing uuid?

By default, the DRF API Logger uses uuid.uuid4() to generate tracing id. If you want to use your custom function to generate uuid, specify DRF_API_LOGGER_TRACING_FUNC in the setting.py file.

DRF_API_LOGGER_TRACING_FUNC = 'foo.bar.func_name'

Tracing already present in headers?

If the tracing ID is already coming as a part of request headers, you can specify the header name.

DRF_API_LOGGER_TRACING_ID_HEADER_NAME: str = 'X_TRACING_ID'  # Replace with actual header name.

API with or without Host

You can specify whether an endpoint of API should have absolute URI or not by setting this variable in the DRF settings.py file.

DRF_API_LOGGER_PATH_TYPE = 'ABSOLUTE'  # Default to ABSOLUTE if not specified
# Possible values are ABSOLUTE, FULL_PATH or RAW_URI

Considering we are accessing the following URL: http://127.0.0.1:8000/api/v1/?page=123 DRF_API_LOGGER_PATH_TYPE possible values are:

  1. ABSOLUTE (Default) :

    Function used request.build_absolute_uri()

    Output: http://127.0.0.1:8000/api/v1/?page=123

  2. FULL_PATH

    Function used request.get_full_path()

    Output: /api/v1/?page=123

  3. RAW_URI

    Function used request.get_raw_uri()

    Output: http://127.0.0.1:8000/api/v1/?page=123

    Note: Similar to ABSOLUTE but skip allowed hosts protection, so may return an insecure URI.

Use the DRF API Logger Model to query

You can use the DRF API Logger Model to query some information.

Note: Make sure to set "DRF_API_LOGGER_DATABASE = True" in the settings.py file.

from drf_api_logger.models import APILogsModel

"""
Example:
Select records for status_code 200.
"""

result_for_200_status_code = APILogsModel.objects.filter(status_code=200)

DRF API Logger Model:

class APILogsModel(Model):
   id = models.BigAutoField(primary_key=True)
   api = models.CharField(max_length=1024, help_text='API URL')
   headers = models.TextField()
   body = models.TextField()
   method = models.CharField(max_length=10, db_index=True)
   client_ip_address = models.CharField(max_length=50)
   response = models.TextField()
   status_code = models.PositiveSmallIntegerField(help_text='Response status code', db_index=True)
   execution_time = models.DecimalField(decimal_places=5, max_digits=8,
                                       help_text='Server execution time (Not complete response time.)')
   added_on = models.DateTimeField()
   
   def __str__(self):
      return self.api

   class Meta:
      db_table = 'drf_api_logs'
      verbose_name = 'API Log'
      verbose_name_plural = 'API Logs'

Note:

After some time, there will be too much data in the database. Searching and filtering may get slower. If you want, you can delete or archive the older data. To improve the searching or filtering, try to add indexes in the 'drf_api_logs' table.

drf-api-logger's People

Contributors

abe-101 avatar davidromanovizc avatar dfrankow avatar etuloser avatar hassan-elseoudy avatar kylepollina avatar mertcangokgoz avatar omarnunezg avatar protages avatar roshenmaghhan avatar viokingtung avatar vishalanandl177 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

drf-api-logger's Issues

Body not logged

I'm using Postman and the body field remains empty. The payload isn't being logged!
I've set it up as per the readme!
Any suggestions would be really appreciated!
@vishalanandl177

Make table creation independent of DRF_API_LOGGER_DATABASE

Usage of multiple schemas with DRF_API_LOGGER_DATABASE does not work, because DRF-API-Logger is not aware of different schemas. The option is to use a logger signal and disable automatic logs. Unfortunately when DRF_API_LOGGER_DATABASE is set to false all database migrations are not applied.

Solution:
Make database migrations and all model function independent from DRF_API_LOGGER_DATABASE.

Log into another database is not working

I have added the settings for different db for logs
DRF_API_LOGGER_DEFAULT_DATABASE = 'logs'

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DATABASE_NAME'),
'USER': os.environ.get('DATABASE_USER'),
'PASSWORD': os.environ.get('DATABASE_PASSWORD'),
'HOST': os.environ.get('DATABASE_HOST', 'localhost'),
'PORT': os.environ.get('DATABASE_PORT', 5432),
},
'logs': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('LOGS_DATABASE_NAME'),
'USER': os.environ.get('LOGS_DATABASE_USER'),
'PASSWORD': os.environ.get('LOGS_DATABASE_PASSWORD'),
'HOST': os.environ.get('LOGS_DATABASE_HOST', 'localhost'),
'PORT': os.environ.get('LOGS_DATABASE_PORT', 5432),
}
}

But it shows error in django admin
ProgrammingError at /manage-console/drf_api_logger/apilogsmodel/

relation "drf_api_logs" does not exist
LINE 1: SELECT COUNT(*) AS "__count" FROM "drf_api_logs" WHERE ("drf...

Throws exception if Host header is missing

drf-api-logger throws an exception where there is no Host header in the request.

api_logger_middleware.py", line 93, in __call__
    host = request.META['HTTP_HOST']
KeyError: 'HTTP_HOST'

I noticed this when running unit tests with the api logger enabled.

How to skip some path of my project?

Can have an configuration example of the parameter DRF_API_LOGGER_SKIP_URL_NAME?
I want to know how to skip some path in my project.
Thank you in advance

DOMGA

Logging of login credentials

Hi,
I installed this package some days ago and Im really happy with it!
However, I have noticed that the logger also logs the password unencrypted to the database if REST auth is used because it's part of the request.
Is there an option to disable or encrypt the password in the requests?

JUST APIs with response 200 are logged?

Hi, thank you for this amazing package.
Following your set-up it looks like I am able to log just APIis that have 200 errors;

Any idea?

(A part from adding it in middleware and installeds app)

Store API Logger to Database

DRF_API_LOGGER_DATABASE = True # Default to False
DRF_LOGGER_QUEUE_MAX_SIZE = 100
DRF_LOGGER_INTERVAL = 10

hide sensitive information from being exposed in the logs

DRF_API_LOGGER_EXCLUDE_KEYS = ['password', 'token', 'access', 'refresh']

@vishalanandl177

Logger only one api

Can you prompt, if need logger only for some api - how I can do it? exist DRF_API_LOGGER_SKIP_NAMESPACE and DRF_API_LOGGER_SKIP_URL_NAME, but all enumerate - its bad and can something forgot.

Does not log a malformed POST body

I am not sure, but I believe that if there is an error parsing a POST body, possibly it does not capture the body.

Here's what I see in the Django admin UI:

image

Unfortunately, I'm not quite sure how to easily set up a reproducible test case in your code repo. Suggestions welcome.

Migrations not distributed in package

Thanks for this package. I'm excited to try it.

When I got it, it needed a migration, but that migration isn't saved in the package.

$ ./manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, ..., sessions
Running migrations:
  No migrations to apply.
  Your models have changes that are not yet reflected in a migration, and so won't be applied.
  Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.

$ ./manage.py makemigrations
Migrations for 'drf_api_logger':
  .venv/lib/python3.9/site-packages/drf_api_logger/migrations/0001_initial.py
    - Create model APILogsModel

I believe you should make the migration and check it in.

I could probably produce a pull request if you wish.

KeyError at /manage-console/drf_api_logger/apilogsmodel/ 'cl'

Internal Server Error: /manage-console/drf_api_logger/apilogsmodel/
Traceback (most recent call last):
File "/Python/env/lib/python3.8/site-packages/asgiref/sync.py", line 458, in thread_handler
raise exc_info[1]
File "/Python/env/lib/python3.8/site-packages/django/core/handlers/exception.py", line 38, in inner
response = await get_response(request)
File "/Python/env/lib/python3.8/site-packages/django/core/handlers/base.py", line 233, in _get_response_async
response = await wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Python/env/lib/python3.8/site-packages/asgiref/sync.py", line 423, in call
ret = await asyncio.wait_for(future, timeout=None)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/tasks.py", line 455, in wait_for
return await fut
File "/Python/env/lib/python3.8/site-packages/asgiref/current_thread_executor.py", line 22, in run
result = self.fn(*self.args, **self.kwargs)
File "/Python/env/lib/python3.8/site-packages/asgiref/sync.py", line 462, in thread_handler
return func(*args, **kwargs)
File "/Python/env/lib/python3.8/site-packages/django/contrib/admin/options.py", line 616, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "/Python/env/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
response = view_func(request, *args, **kwargs)
File "/Python/env/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
response = view_func(request, *args, **kwargs)
File "/Python/env/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 232, in inner
return view(request, *args, **kwargs)
File "/Python/env/lib/python3.8/site-packages/drf_api_logger/admin.py", line 90, in changelist_view
filtered_query_set = response.context_data["cl"].queryset
KeyError: 'cl'

This is happening when i try to delete all the logs from django admin

Allow logging of DELETE requests

Have you considered adding logging of DELETE requests? These are not logged now since they do not have a content-type, but deleting resources seems to be something you would want to log. I've patched my copy and it's only a few lines of code changes to allow it to log DELETE requests also.

Add Username to log messages

Please
Is it possible this package to add the username or user ID (if available) to the log messages?
Thank you in advance for your response

drf_api_logger is not logging API request from production environment which is https:

Everything is perfectly working in development environment. All my APIs that I am using POSTMAN desktop application is logging in drf_api_logger model. In nutshell all is working perfect as what I am looking. But once I transfer my code to production environment drf_api_logger is not logging any API calls from POSTMAN from both version desktop and web base POSTMAN.

I tried by looking options in drf_api_logger documentation, nothing works. One thing I noticed the difference in development and production is of "http" vs "https".

Can you please advice how I can make drf_api_logger to work for my production environment.

Logging everything

I made some tests and it seems that:

It logs all the API information for content type "application/json".

Does not seem to hold true.

Version drf-api-logger==1.0.5 seems to be logging all types of requests.

The response field is skipped, but the entry is created.

500 not logged

I have configured the app and tested for 500 status but api does not logged 500 status, though it logged 200, 400. I am following default configuration.

Deprecation warning

When I run tests with pytest, I get:

src/apps/accounts/tests/test_endpoint_post_login.py::test_happy_path
  /usr/local/lib/python3.10/site-packages/drf_api_logger/start_logger_when_server_starts.py:14: DeprecationWarning: getName() is deprecated, get the name attribute instead
    if t.getName() == LOG_THREAD_NAME:

src/apps/accounts/tests/test_endpoint_post_login.py::test_happy_path
  /usr/local/lib/python3.10/site-packages/drf_api_logger/start_logger_when_server_starts.py:20: DeprecationWarning: setName() is deprecated, set the name attribute instead
    t.setName(LOG_THREAD_NAME)

Unable to destroy test db after using this library.

Everything was working fine, after install this lib my django test CI failed. Test database is not destroying and raising
I am 100% sure, session is used by drf-api-logger.

django.db.utils.OperationalError: database "test_betrics_db" is being accessed by other users DETAIL: There is 1 other session using the database.

Increase api field length

There are few apis which consists of long query params like
{{protocol}}://{{base_url}}/api/v1/configurations/area-templates/?search=searchstring&service=6&sub_location=9&sub_location=8&sub_location=7&fields=name,id&service_location=2&service_location=3&section=1&section=2&section=3&section=4&section=5&section=6&section=7&section=8&section=9&section=10&section=11&section=12&section=13&section=14&section=15&section=16&section=17&section=18&section=19&section=20&section=21&section=22&no_page

but according to the model field, this can only save 512 chars and raise
*** django.db.utils.DataError: value too long for type character varying(512)

class APILogsModel(BaseModel):
    api = models.CharField(max_length=512, help_text='API URL')

How to filter specific user using JWT?

Overview

The JWT token is stored in the headers as follows.

headers:

{
"AUTHORIZATION": "Bearer [JWT]",
}

When a user sends a GET /log request, I want to filter the APILogsModel based on user_id. (i.e. users can only see their own request history)

Pseudo code:

class LogView(generics.ListAPIView):
    serializer_class = LogSerializer

    def get_queryset(self):
        token_str = self.request.META.get("HTTP_AUTHORIZATION", " ").split(" ")[1]
        access_token = AccessToken(token_str)

        ##################################################
        Filter by access_token
        ##################################################

        return queryset

Problem

There is no field for user information in APILogsModel. Therefore, it must be extracted from the JWT stored in headers. However, it seems inefficient to extract it from all headers every time a request comes in.

Conclusion

Is there any other efficient way? (Is it possible to override a model or middleware?)

FileNotFoundError: [Errno 2] No such file or directory: 'README.md'

Please update your setup.py in https://files.pythonhosted.org/packages/e0/26/6c903af8943b1f91584401d122e8d62ca4d2b778245f2afaee37a12484db/drf_api_logger-1.0.3.tar.gz#sha256=3b0dab7b0ccd9035425a18d0599d7f0a56c28a17108a02aa667e8a61fb50efdc

Error
```
ERROR: Command errored out with exit status 1:
command: /usr/local/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-kuuj6y0c/drf-api-logger_49ecd2f8baa1419691e19dcc415c23a3/setup.py'"'"'; file='"'"'/tmp/pip-install-kuuj6y0c/drf-api-logger_49ecd2f8baa1419691e19dcc415c23a3/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(file);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-pip-egg-info-pu29f_p6
cwd: /tmp/pip-install-kuuj6y0c/drf-api-logger_49ecd2f8baa1419691e19dcc415c23a3/
Complete output (7 lines):
Traceback (most recent call last):
File "", line 1, in
File "/tmp/pip-install-kuuj6y0c/drf-api-logger_49ecd2f8baa1419691e19dcc415c23a3/setup.py", line 16, in
long_description=get_long_desc(),
File "/tmp/pip-install-kuuj6y0c/drf-api-logger_49ecd2f8baa1419691e19dcc415c23a3/setup.py", line 5, in get_long_desc
with open("README.md", "r") as fh:
FileNotFoundError: [Errno 2] No such file or directory: 'README.md'
----------------------------------------
WARNING: Discarding https://files.pythonhosted.org/packages/e0/26/6c903af8943b1f91584401d122e8d62ca4d2b778245f2afaee37a12484db/drf_api_logger-1.0.3.tar.gz#sha256=3b0dab7b0ccd9035425a18d0599d7f0a56c28a17108a02aa667e8a61fb50efdc (from https://pypi.org/simple/drf-api-logger/) (requires-python:>=3.5). Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
ERROR: Could not find a version that satisfies the requirement drf-api-logger==1.0.3
ERROR: No matching distribution found for drf-api-logger==1.0.3


you have spelling mistake in reading README.md file in setup.py

api field should be a TextField

@vishalanandl177
I thing you should update api field in APILogsModel into TextField. The reason is, when we use ModelMultipleChoiceFilter in filterset class, it creates extra long urls like, /api/v1/events/inspections/widgets/?&client=6&client=5&client=2&widget=top_service_locations
Right now the max_length=1024 of api field and if URL goes long than 1024, you package will throw error.
Thanks!

Don't write response with method get

Hey,

It's not an issue, but an feature request.
Is there a possibility to skip the response in case of get Method and response code 200?
after one day I've got about 200MB of data overhead due to this.

I disabled now the logging for get requests.

Thank you in advance!

User Details to Logs

Is there any way to add user details to the logs for eg: username or user id.

404 error on non-root deployment

When deploying on a non-root path i.e. http://myserver.com/myapp/ the drf-api-logger middleware reports a 404 on all routes. This can easily be reproduced on a dev server by specifying FORCE_SCRIPT_NAME="/myapp/" in settings.py

The problem is request.path contains the myapp prefix and the path does not resolve. Switching to request.path_info will fix this.

Nothing apache-specific about it but I think this is what the person who reported #23 was experiencing.

UUID field not serializable in middleware

TypeError: Object of type UUID is not JSON serializable

Specifically here: d['headers'] = json.dumps(d['headers'], indent=4)

The field is of type uuid.UUID .

I have found using the DjangoJSONEncoder allows for the encoding of these odd django fields
d['headers'] = json.dumps(d['headers'], indent=4, cls=DjangoJSONEncoder)

Bug in APILoggerMiddleware

Hi,
Great thanks, for this package!
I got bug from django "KeyError: 'content-type' in APILoggerMiddleware"

probably, you should use method ".get()" to get key 'content-type' from response

line 76:
if 'content-type' in response and
response.get('content-type') == 'application/json' or
response.get('content-type') == 'application/vnd.api+json':

Store Log in cloudwatch

hello,

is it possible to store log in aws cloudwatch instead of the database? I am trying to achieve it using watchtower

404 when used with apache

The issue still persists therefore I reopen the issue. Check the new comment on the related issue. #23

Thanks in advance...

Enabling Sites Framework,

Django sites framework implementation is not considered. When using sites, app shows both application's api calls.

Follow README but log nothing

Hi,

I follow README to add app, middleware and some settings in settings.py.

The admin panel have new page: http://localhost/admin/drf_api_logger/apilogsmodel/

But no log show up.

I called API work as expect.

method = GET
url = http://localhost:3000/

response = Hello!!

Django log

Performing system checks...

Watching for file changes with StatReloader
System check identified no issues (0 silenced).
October 16, 2022 - 11:49:57
Django version 3.2.16, using settings 'DrfLogTest.settings'
Starting development server at http://0.0.0.0:3000/
Quit the server with CTRL-BREAK.
[16/Oct/2022 11:50:09] "GET /admin/drf_api_logger/apilogsmodel/ HTTP/1.1" 200 8690
[16/Oct/2022 11:50:09] "GET /admin/jsi18n/ HTTP/1.1" 200 3195
[16/Oct/2022 11:50:13] "GET / HTTP/1.1" 200 140
[16/Oct/2022 11:50:14] "GET / HTTP/1.1" 200 140
[16/Oct/2022 11:50:15] "GET / HTTP/1.1" 200 140
[16/Oct/2022 11:50:15] "GET / HTTP/1.1" 200 140
[16/Oct/2022 11:50:15] "GET / HTTP/1.1" 200 140
[16/Oct/2022 11:50:15] "GET / HTTP/1.1" 200 140
[16/Oct/2022 11:50:15] "GET / HTTP/1.1" 200 140

I also copy the signal example code and it doesn't print anything either.

Is there anything I forget to setup??

Run pip freeze

asgiref==3.5.2
beautifulsoup4==4.11.1
bleach==5.0.1
bs4==0.0.1
certifi==2022.9.24
charset-normalizer==2.1.1
Django==4.1.2
django-tables2==2.4.1
djangorestframework==3.14.0
drf-api-logger==1.1.11
idna==3.4
keyboard==0.13.5
psycopg2==2.9.4
python-vlc==3.0.16120
pytz==2022.4
requests==2.28.1
six==1.16.0
soupsieve==2.3.2.post1
sqlparse==0.4.3
typing-extensions==4.4.0
urllib3==1.26.12
webencodings==0.5.1

settings.py as follow.

"""
Django settings for DrfLogTest project.

Generated by 'django-admin startproject' using Django 3.0.5.

For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
from config import database_config

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '$t=lyl(()ytv0%vx9^^o_-zivv%upc&&n0o#l4%g#=o!u07!m0'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['*']

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'django_tables2',

    'rest_framework',
    'crawler',

    'drf_api_logger',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    'drf_api_logger.middleware.api_logger_middleware.APILoggerMiddleware',
]

ROOT_URLCONF = 'DrfLogTest.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'DrfLogTest.wsgi.application'

# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3')
        # 'ENGINE': 'django.db.backends.postgresql_psycopg2',
        # 'NAME': database_config.name,
        # 'USER': database_config.user,
        # 'PASSWORD': database_config.password,
        # 'HOST': database_config.host,
        # 'PORT': database_config.port,
    }
}

# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'

SITE_ID = 1

# drf logger
DRF_API_LOGGER_DATABASE = True
DRF_API_LOGGER_SIGNAL = True
DRF_API_LOGGER_METHODS = ['GET', 'POST', 'DELETE', 'PUT']
DRF_API_LOGGER_STATUS_CODES = ['200', '400', '404', '500']
DRF_LOGGER_QUEUE_MAX_SIZE = 1
DRF_LOGGER_INTERVAL = 1

DRF_API_LOGGER_EXCLUDE_KEYS

Hi guys.
There is a suggestion to leave the user the ability to change the default exceptions

SENSITIVE_KEYS = ['password', 'token', 'access', 'refresh']
if hasattr(settings, 'DRF_API_LOGGER_EXCLUDE_KEYS'):
if type(settings.DRF_API_LOGGER_EXCLUDE_KEYS) in (list, tuple):
SENSITIVE_KEYS.extend(settings.DRF_API_LOGGER_EXCLUDE_KEYS)

SENSITIVE_KEYS = settings.DRF_API_LOGGER_EXCLUDE_KEYS

Add support for list of dicts in mask_sensitive_data() util function

Below code snippet might helpful.

SENSITIVE_KEYS = ['password']

def mask_sensitive_data(data):
    """
    Hides sensitive keys specified in sensitive_keys settings.
    Loops recursively over nested dictionaries.
    """

    if type(data) != dict:
      return data

    for key, value in data.items():
      if key in SENSITIVE_KEYS:
        data[key] = "***FILTERED***"

      if type(value) == dict:
        data[key] = mask_sensitive_data(data[key])
      
      # // new code
      if type(value) == list:
          data[key] = [mask_sensitive_data(item) for item in data[key]]

    return data


input_data = {"username":"any name", "password": "pass",
     "extra": {"email":"mail@sample", "password": "pass"},
     "list_items":[{"username":"blah", "password": "blah"}]}

masked_data = mask_sensitive_data(input_data)
print(masked_data)

Filter request logs by users

One functionality i'll find useful is the ability to filter requests by a certain user for debugging purpose.
Perhaps an api is slow or failing for a certain user. Not sure if this is desirable for the entire project. I'll like to open a PR for it if it is. @vishalanandl177

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.