Skip to content

Commit

Permalink
Update Readme for Gunicorn on MacOS and slight optimization (#90)
Browse files Browse the repository at this point in the history
* add optimization

* Add trouble shoot section

* remove unneeded text

* bump version
  • Loading branch information
xinghengwang authored Dec 16, 2024
1 parent d42ecf3 commit 332a8df
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 52 deletions.
98 changes: 53 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ by [Moesif](https://moesif.com), the [API analytics](https://www.moesif.com/feat
[![Software License][ico-license]][link-license]
[![Source Code][ico-source]][link-source]

Moesif middleware for Django automatically logs incoming and outgoing API calls
Moesif middleware for Django automatically logs incoming and outgoing API calls
and sends them to [Moesif](https://www.moesif.com) for API analytics and monitoring.

This SDK uses the Requests library and works for Python versions 2.7 up to 3.10.4.
Expand Down Expand Up @@ -87,7 +87,7 @@ MIDDLEWARE = [
]
```

Then add a dictionary `MOESIF_MIDDLEWARE` to your Django settings file:
Then add a dictionary `MOESIF_MIDDLEWARE` to your Django settings file:

```
MOESIF_MIDDLEWARE = {
Expand All @@ -108,7 +108,7 @@ MIDDLEWARE_CLASSES = [
]
```

Then add a dictionary `MOESIF_MIDDLEWARE` to your Django settings file:
Then add a dictionary `MOESIF_MIDDLEWARE` to your Django settings file:
```
MOESIF_MIDDLEWARE = {
Expand All @@ -117,7 +117,7 @@ MOESIF_MIDDLEWARE = {
}
```

The dictionary contains the [configuration options](#configuration-options) for
The dictionary contains the [configuration options](#configuration-options) for
the middleware, including your [Moesif Application ID](#get-your-moesif-application-id) that you must specify.

### Optional: Capturing Outgoing API Calls
Expand Down Expand Up @@ -241,10 +241,10 @@ This function takes Requests [`Request` and `Response` objects](https://requests

Optional, but highly recommended.

This function takes a request and a response and returns a string that represents
This function takes a request and a response and returns a string that represents
the user ID used by your system.

Moesif tries to identify users automatically and fetch the username from [`django.http.HttpRequest.user`](https://docs.djangoproject.com/en/1.8/ref/request-response/#django.http.HttpRequest.user). However, if implementation differs, we highly recommend that you accurately provide a
Moesif tries to identify users automatically and fetch the username from [`django.http.HttpRequest.user`](https://docs.djangoproject.com/en/1.8/ref/request-response/#django.http.HttpRequest.user). However, if implementation differs, we highly recommend that you accurately provide a
user ID using this function.

#### `IDENTIFY_COMPANY`
Expand Down Expand Up @@ -303,9 +303,9 @@ A function that takes a request and a response and returns a string that represe
</tr>
</table>

Optional.
Optional.

A function that takes a request and a response, and returns a string that represents the session token for this event.
A function that takes a request and a response, and returns a string that represents the session token for this event.

Similar to [user IDs](#identify_user), Moesif tries to get the session token automatically. However, if you setup differs from the standard, this function can help tying up events together and help you replay the events.

Expand Down Expand Up @@ -365,7 +365,7 @@ Optional.

Whether to log request and response body to Moesif.

Set to `False` to remove the HTTP body before sending to Moesif.
Set to `False` to remove the HTTP body before sending to Moesif.

If you want more control over which fields the middleware includes or not, see the next option `MASK_EVENT_MODEL`.

Expand Down Expand Up @@ -397,9 +397,9 @@ If you want more control over which fields the middleware includes or not, see t

Optional.

A function that takes the final Moesif event model and returns an `EventModel` object with desired data removed.
A function that takes the final Moesif event model and returns an `EventModel` object with desired data removed.

Use this if you prefer to write your own mask function than uses the string based filter options:
Use this if you prefer to write your own mask function than uses the string based filter options:

- `REQUEST_BODY_MASKS`
- `REQUEST_HEADER_MASKS`
Expand Down Expand Up @@ -454,7 +454,7 @@ Specifies the maximum batch size when sending to Moesif.

Optional.

The maximum number of events to hold in queue before sending to Moesif.
The maximum number of events to hold in queue before sending to Moesif.

In case of network issues, the middleware may fail to connect or send event to Moesif. In those cases, the middleware skips adding new to event to queue to prevent memory overflow.

Expand All @@ -465,7 +465,7 @@ In case of network issues, the middleware may fail to connect or send event to M
Data type
</th>
<th scope="col">
Default
Default
</th>
</tr>
<tr>
Expand All @@ -489,7 +489,7 @@ A request header field name used to identify the User in Moesif. It also support
Data type
</th>
<th scope="col">
Default
Default
</th>
</tr>
<tr>
Expand Down Expand Up @@ -524,7 +524,7 @@ Optional.

A local proxy hostname when sending traffic through secure proxy. Remember to set this field when using secure proxy. For more information, see [Secure Proxy documentation.](https://www.moesif.com/docs/platform/secure-proxy/#2-configure-moesif-sdk).

### Options For Outgoing API Calls
### Options For Outgoing API Calls

The following options apply to outgoing API calls. These are calls you initiate using the Python [Requests](http://docs.python-requests.org/en/master/) library to third parties like Stripe or to your own services.

Expand All @@ -539,7 +539,7 @@ If you are not using Django, you can import [`moesifpythonrequest`](https://gith
Data type
</th>
<th scope="col">
Default
Default
</th>
</tr>
<tr>
Expand Down Expand Up @@ -584,7 +584,7 @@ Optional.

A function that enables you to return custom metadata associated with the logged API calls.

Takes in the [Requests](http://docs.python-requests.org/en/master/api/) request and response objects as arguments.
Takes in the [Requests](http://docs.python-requests.org/en/master/api/) request and response objects as arguments.

We recommend that you implement a function that
returns a dictionary containing your custom metadata. The dictionary must be a valid one that can be encoded into JSON. For example, you may want to save a virtual machine instance ID, a trace ID, or a resource ID with the request.
Expand Down Expand Up @@ -648,9 +648,9 @@ and returns `True` if you want to skip this particular event.

Optional, but highly recommended.

A function that takes [Requests](http://docs.python-requests.org/en/master/api/) request and response objects, and returns a string that represents the user ID used by your system.
A function that takes [Requests](http://docs.python-requests.org/en/master/api/) request and response objects, and returns a string that represents the user ID used by your system.

While Moesif tries to identify users automatically, different frameworks and your implementation might vary. So we highly recommend that you accurately provide a
While Moesif tries to identify users automatically, different frameworks and your implementation might vary. So we highly recommend that you accurately provide a
user ID using this function.

##### `IDENTIFY_COMPANY_OUTGOING`
Expand Down Expand Up @@ -711,7 +711,7 @@ A function that takes [Requests](http://docs.python-requests.org/en/master/api/)

Optional.

A function that takes [Requests](http://docs.python-requests.org/en/master/api/) request and response objects, and returns a string that corresponds to the session token for this event.
A function that takes [Requests](http://docs.python-requests.org/en/master/api/) request and response objects, and returns a string that corresponds to the session token for this event.

Similar to [user IDs](#identify_user_outgoing), Moesif tries to get the session token automatically. However, if you setup differs from the standard, this function can help tying up events together and help you replay the events.

Expand Down Expand Up @@ -827,7 +827,7 @@ user = {
'company_id': '67890', # If set, associate user with a company object
'campaign': {
'utm_source': 'google',
'utm_medium': 'cpc',
'utm_medium': 'cpc',
'utm_campaign': 'adwords',
'utm_term': 'api+tooling',
'utm_content': 'landing'
Expand Down Expand Up @@ -908,10 +908,10 @@ middleware = MoesifMiddleware(None)
# metadata can be any custom object
company = {
'company_id': '67890',
'company_domain': 'acmeinc.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'company_domain': 'acmeinc.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'campaign': {
'utm_source': 'google',
'utm_medium': 'cpc',
'utm_medium': 'cpc',
'utm_campaign': 'adwords',
'utm_term': 'api+tooling',
'utm_content': 'landing'
Expand Down Expand Up @@ -943,7 +943,7 @@ middleware = MoesifMiddleware(None)

companyA = {
'company_id': '67890',
'company_domain': 'acmeinc.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'company_domain': 'acmeinc.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'metadata': {
'org_name': 'Acme, Inc',
'plan_name': 'Free',
Expand All @@ -958,7 +958,7 @@ companyA = {

companyB = {
'company_id': '09876',
'company_domain': 'contoso.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'company_domain': 'contoso.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'metadata': {
'org_name': 'Contoso, Inc',
'plan_name': 'Free',
Expand Down Expand Up @@ -1005,13 +1005,13 @@ subscription = {
update_subscription = middleware.update_subscription(subscription)
```

The `metadata` field can store any subscription-related information. Moesif only requires the the following fields:
The `metadata` field can store any subscription-related information. Moesif only requires the the following fields:

- `subscription_id`
- `company_id`
- `status`
- `status`

This method is a convenient helper that calls the Moesif API library.
This method is a convenient helper that calls the Moesif API library.

For more information, see [Moesif Python API reference](https://www.moesif.com/docs/api?python#update-a-subscription).

Expand Down Expand Up @@ -1052,32 +1052,32 @@ subscriptionB = {
update_subscriptions = middleware.update_subscriptions_batch([subscriptionA, subscriptionB])
```

The `metadata` field can store any subscription-related information. Moesif only requires the the following fields:
The `metadata` field can store any subscription-related information. Moesif only requires the the following fields:

- `subscription_id`
- `company_id`
- `status`
- `status`

This method is a convenient helper that calls the Moesif API library.
This method is a convenient helper that calls the Moesif API library.

For more information, see [Moesif Python API reference](https://www.moesif.com/docs/api?python#update-subscriptions-in-batch).

## Tested Python and Django Versions

Moesif has validated this middleware against the following combinations of Python and Django versions:

| Python | Django |
| ------------ | ------- |
| Python 2.7 | 1.11.22 |
| Python 2.7 | 1.11.22 |
| Python 2.7 | 1.9 |
| Python 3.4.5 | 1.11.22 |
| Python 3.4.5 | 1.11.22 |
| Python 3.4.5 | 1.9 |
| Python 3.6.4 | 1.11.22 |
| Python 3.6.4 | 1.11.22 |
| Python 3.6.4 | 1.9 |
| Python 3.10.4 | 3.2.13 LTS |
| Python | Django |
| ------------ | ------- |
| Python 2.7 | 1.11.22 |
| Python 2.7 | 1.11.22 |
| Python 2.7 | 1.9 |
| Python 3.4.5 | 1.11.22 |
| Python 3.4.5 | 1.11.22 |
| Python 3.4.5 | 1.9 |
| Python 3.6.4 | 1.11.22 |
| Python 3.6.4 | 1.11.22 |
| Python 3.6.4 | 1.9 |
| Python 3.10.4 | 3.2.13 LTS |
| Python 3.10.4 | 4.0.5 |

## How to Test
Expand All @@ -1086,11 +1086,19 @@ Moesif has validated this middleware against the following combinations of Pytho
3. Run `pip install Django` and then run `pip install moesifdjango`.
4. Add your [Moesif Application ID](#get-your-moesif-application-id) to `tests/settings.py`.
5. From terminal, navigate to the root directory of the middleware tests `tests/`.

a. Run `python manage.py test` if you are using Django 1.10 or newer.

b. Run `python manage.py test middleware_pre19_tests` if you are using Django 1.9 or older.

## Troubleshoot

On MacOS, with `gunicorn`, it is possible to encounter this error: "in progress in another thread when fork() was called". Solution is to add `--preload` option when launching `gunicorn` like below.

```bash
gunicorn myapp.wsgi:application --bind 127.0.0.1:8000 --preload
```

## Explore Other Integrations

Explore other integration options from Moesif:
Expand Down
2 changes: 1 addition & 1 deletion moesifdjango/logger_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def parse_request_headers(self, request, middleware_settings, debug):
req_headers = {}

if debug:
logger.info("about to print what is in meta %d " % len(request.META))
logger.info("checking request meta %d " % len(request.META))
for x in request.META:
logger.info(f'{x}: {request.META[x]}')
logger.info("about to print headers %d " % len(req_headers))
Expand Down
9 changes: 5 additions & 4 deletions moesifdjango/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def __init__(self, get_response):
self.client = MoesifAPIClient(self.middleware_settings.get('APPLICATION_ID'))
self.logger_helper = LoggerHelper()
Configuration.BASE_URI = self.logger_helper.get_configuration_uri(self.middleware_settings, 'BASE_URI', 'LOCAL_MOESIF_BASEURL')
Configuration.version = 'moesifdjango-python/2.3.11'
Configuration.version = 'moesifdjango-python/2.3.12'
if settings.MOESIF_MIDDLEWARE.get('CAPTURE_OUTGOING_REQUESTS', False):
try:
if self.DEBUG:
Expand Down Expand Up @@ -167,9 +167,10 @@ def __call__(self, request):
transaction_id = None

try:
request._mo_body = request.body
request._stream = BytesIO(request.body)
request._read_started = False
if self.LOG_BODY:
request._mo_body = request.body
request._stream = BytesIO(request.body)
request._read_started = False
except:
request._mo_body = None

Expand Down
2 changes: 1 addition & 1 deletion moesifdjango/middleware_pre19.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(self):
self.client = MoesifAPIClient(self.middleware_settings.get('APPLICATION_ID'))
self.logger_helper = LoggerHelper()
Configuration.BASE_URI = self.logger_helper.get_configuration_uri(self.middleware_settings, 'BASE_URI', 'LOCAL_MOESIF_BASEURL')
Configuration.version = 'moesifdjango-python/2.3.11'
Configuration.version = 'moesifdjango-python/2.3.12'
if settings.MOESIF_MIDDLEWARE.get('CAPTURE_OUTGOING_REQUESTS', False):
try:
if self.DEBUG:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
# Versions should comply with PEP440. For a discussion on single-sourcing
# the version across setup.py and the project code, see
# https://packaging.python.org/en/latest/single_source_version.html
version='2.3.11',
version='2.3.12',

description='Moesif Middleware for Python Django',
long_description=long_description,
Expand Down

0 comments on commit 332a8df

Please sign in to comment.