Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jf/find #64

Merged
merged 16 commits into from
Oct 2, 2016
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Change Log
==========

v0.8.0
------
* Mongolog.find utility for searching the logs
* flake8 compliance (mostly)

v0.7.4
------
* Added base paramter 'max_keep' that is used for embedded documents to determine how many records to keep
Expand Down
21 changes: 9 additions & 12 deletions build.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
#!/usr/bin/env python
import os
import subprocess
import collections

COPY_PATH=os.path.expanduser(
os.path.abspath(
os.environ.get("MONGOLOG_COPY_PATH", "./")
)
COPY_PATH = os.path.expanduser(
os.path.abspath(
os.environ.get("MONGOLOG_COPY_PATH", "./")
)
)
if not COPY_PATH:
raise ValueError("You muse set MONGOLOG_COPY_PATH")
raise ValueError("You muse set MONGOLOG_COPY_PATH")

Commands = (
"rm -rf dist",
"python setup.py sdist",
"python setup.py sdist",
)


for cmd in Commands:
print "running:", " ".join(cmd.split())
subprocess.check_output(cmd.split())

print("running:", " ".join(cmd.split()))
subprocess.check_output(cmd.split())

## Now copy the file over
# Now copy the file over
cmd = "cp ./dist/%s %s" % (os.listdir("dist")[0], COPY_PATH)
subprocess.check_output(cmd.split())
4 changes: 2 additions & 2 deletions mongolog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"""
from .handlers import ( # noqa
BaseMongoLogHandler,
SimpleMongoLogHandler,
VerboseMongoLogHandler,
SimpleMongoLogHandler,
VerboseMongoLogHandler,
HttpLogHandler,
)
5 changes: 3 additions & 2 deletions mongolog/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python


class MissingConnectionError(ValueError):
def __init__(self, *args, **kwargs):
ValueError.__init__(self, *args, **kwargs)
def __init__(self, *args, **kwargs):
ValueError.__init__(self, *args, **kwargs)
53 changes: 27 additions & 26 deletions mongolog/handlers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
# !/usr/bin/env python
"""
django-mongolog. Simple Mongo based logger for Django
Copyright (C) 2015 - John Furr
Expand Down Expand Up @@ -39,16 +39,19 @@
uuid_namespace = uuid.UUID('8296424f-28b7-5982-a434-e6ec8ef529b3')


def get_mongolog_handler(logger_name=None):
# TODO Move to mongolog.models.Mongolog
def get_mongolog_handler(logger_name=None, show_logger_names=False):
"""
Return the first MongoLogHander found in the list of defined loggers.
Return the first MongoLogHander found in the list of defined loggers.
NOTE: If more than one is defined, only the first one is used.
"""
if logger_name:
logger_names = [logger_name]
else:
logger_names = [''] + list(logging.Logger.manager.loggerDict)
console.info("get_mongolog_handler(): Logger_names: %s", json.dumps(logger_names, indent=4, sort_keys=True))

if show_logger_names:
console.info("get_mongolog_handler(): Logger_names: %s", json.dumps(logger_names, indent=4, sort_keys=True, default=str))

for name in logger_names:
logger = logging.getLogger(name)
Expand Down Expand Up @@ -78,13 +81,13 @@ def __init__(self, level=NOTSET, connection=None, w=1, j=False, verbose=None, ti
valid_record_types = [self.REFERENCE, self.EMBEDDED]
if record_type not in valid_record_types:
raise ValueError("record_type myst be one of %s" % valid_record_types)

# The type of document we store
self.record_type = record_type

# number of dates to keep in embedded document
self.max_keep = max_keep

# The write concern
self.w = w

Expand All @@ -97,7 +100,6 @@ def __init__(self, level=NOTSET, connection=None, w=1, j=False, verbose=None, ti
# If True will print each log_record to console before writing to mongo
self.verbose = verbose

handler_type = str(type(self))
if self.connection:
self.connect()

Expand Down Expand Up @@ -139,11 +141,11 @@ def get_db(self):
"""
Return a handler to the database handler
"""
return getattr(self, "db", None)
return getattr(self, "db", None)

def get_timestamp_collection(self):
return getattr(self, "timestamp", None)

def get_collection(self):
"""
Return the collection being used by MongoLogHandler
Expand All @@ -161,15 +163,15 @@ def connect_pymongo3(self, test=False):
self.client = pymongo.MongoClient(self.connection, serverSelectionTimeoutMS=5, w=self.w)
else:
self.client = pymongo.MongoClient(self.connection, serverSelectionTimeoutMS=5, w=self.w, j=self.j)

except pymongo.errors.ServerSelectionTimeoutError:
msg = "Unable to connect to mongo with (%s)" % self.connection
# NOTE: Trying to log here ends up with Duplicate Key errors on upsert in emit()
print(msg)
raise pymongo.errors.ServerSelectionTimeoutError(msg)

return self.client

def connect_pymongo2(self):
# TODO Determine proper try/except logic for pymongo 2.7 driver
self.client = pymongo.MongoClient(self.connection)
Expand Down Expand Up @@ -201,10 +203,10 @@ def check_keys(self, record):

if isinstance(v, dict):
for old_key in record['msg'][k].keys():
record['msg'][k][self.new_key(old_key)] = record['msg'][k].pop(old_key)
record['msg'][k][self.new_key(old_key)] = record['msg'][k].pop(old_key)

return record

def create_log_record(self, record):
"""
Convert the python LogRecord to a MongoLog Record.
Expand All @@ -223,7 +225,7 @@ def create_log_record(self, record):
uuid_key = str(record['msg']) + str(record['levelname'])
else:
uuid_key = (unicode(record['msg']) + unicode(record['levelname'])).encode('utf-8', 'replace')

record.update({
'uuid': uuid.uuid5(uuid_namespace, uuid_key).hex,
# NOTE: if the user is using django and they have USE_TZ=True in their settings
Expand Down Expand Up @@ -262,9 +264,9 @@ def emit(self, record):

# TODO move this to a validate log_record method and add more validation
log_record.get('uuid', ValueError("You must have a uuid in your LogRecord"))

if self.verbose:
print(json.dumps(log_record, sort_keys=True, indent=4, default=str))
print(json.dumps(log_record, sort_keys=True, indent=4, default=str))

if self.record_type == self.EMBEDDED:
self.insert_embedded(log_record)
Expand Down Expand Up @@ -317,7 +319,7 @@ def reference_log_pymongo_2(self, log_record):

# remove the old document
self.mongolog.find_and_modify(query, remove=True)

# insert the new one
self.mongolog.insert(log_record)

Expand All @@ -337,7 +339,7 @@ def reference_log_pymongo_3(self, log_record):
)

# Now update the timestamp collection
# We can do this with a lower write concern than the previous operation since
# We can do this with a lower write concern than the previous operation since
# we can alway's retreive the last datetime from the mongolog collection
self.timestamp.insert({
'uuid': log_record['uuid'],
Expand Down Expand Up @@ -379,7 +381,7 @@ def create_log_record(self, record):

class VerboseMongoLogHandler(BaseMongoLogHandler):
def create_log_record(self, record):
record = super(VerboseMongoLogHandler, self).create_log_record(record)
record = super(VerboseMongoLogHandler, self).create_log_record(record)
mongolog_record = LogRecord({
'name': record['name'],
'thread': {
Expand All @@ -404,7 +406,7 @@ def create_log_record(self, record):
},
'uuid': record['uuid'],
'time': record['time'],
})
})

if record['exc_info']:
mongolog_record['exception'] = {
Expand All @@ -416,7 +418,7 @@ def create_log_record(self, record):


class HttpLogHandler(SimpleMongoLogHandler):
def __init__(self, level=NOTSET, client_auth='', timeout=3, verbose=False, time_zone="local", *args, **kwargs):
def __init__(self, level=NOTSET, client_auth='', timeout=3, verbose=False, time_zone="local", *args, **kwargs):
# Make sure there is a trailing slash or reqests 2.8.1 will try a GET instead of POST
self.client_auth = client_auth if client_auth.endswith('/') else "%s/" % client_auth

Expand All @@ -426,7 +428,7 @@ def __init__(self, level=NOTSET, client_auth='', timeout=3, verbose=False, time_
self.time_zone = time_zone

# Intentionally hard coded in HttpLogHandler
self.record_type='reference'
self.record_type = 'reference'

# If True will print each log_record to console before writing to mongo
self.verbose = verbose
Expand All @@ -439,7 +441,7 @@ def __unicode__(self):
return u'%s' % self.client_auth

def emit(self, record):
"""
"""
From python: type(record) == LogRecord
https://github.com/certik/python-2.7/blob/master/Lib/logging/__init__.py#L230
"""
Expand All @@ -452,5 +454,4 @@ def emit(self, record):

r = requests.post(self.client_auth, json=json.dumps(log_record, default=str), timeout=self.timeout, proxies={'http':''}) # noqa
# uncomment to debug
print ("Response:", json.dumps(r.json(), indent=4, sort_keys=True, default=str))

print("Response:", json.dumps(r.json(), indent=4, sort_keys=True, default=str))
17 changes: 7 additions & 10 deletions mongolog/management/commands/analog.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
# !/usr/bin/env python
from __future__ import print_function
import logging
import logging.config
import django
import json
import sys

import pymongo
pymongo_version = int(pymongo.version.split(".")[0])
if pymongo_version >= 3:
from pymongo.collection import ReturnDocument
from pymongo.collection import ReturnDocument # noqa: F40


from mongolog.handlers import get_mongolog_handler

from django.core.management.base import BaseCommand

#logger = logging.getLogger(__name__)
logger = logging.getLogger('console')


Expand All @@ -34,13 +32,12 @@ class Command(BaseCommand):
make_option(
'-q', '--query', default=None, action='store', dest='query',
help='Pass in a search query to mongo.'),
)
)

def __init__(self, *args, **kwargs):
super(Command, self).__init__(*args, **kwargs)
self.prev_object_id = None


def add_arguments(self, parser):
if django.VERSION[1] >= 7:
parser.add_argument(
Expand All @@ -58,12 +55,12 @@ def add_arguments(self, parser):

def print_results(self, results):
# older versions of pymongo didn't use a CommandCursor object to iterate over the results.
# We check by trying to convert to a list and if there is a TypeError we continue on
# We check by trying to convert to a list and if there is a TypeError we continue on
# and try to iterate over 'results' as thought it were a Cursor object.
try:
results = list(results['result'])
results.reverse()
except TypeError as e:
except TypeError:
pass

for r in results:
Expand All @@ -78,15 +75,15 @@ def print_results(self, results):
logger.debug(r)
elif level == 'CRITICAL':
logger.critical(r)
elif level == 'MONGOLOG-INTERNAL' or level == None:
elif level == 'MONGOLOG-INTERNAL' or level is None:
# Print nothing if it's a mongolog internal log
pass
else:
raise Exception("level(%s) not found" % level)

def fetch_results(self, options):
query = options['query'] if options['query'] else {}
proj = {'_id': 1, 'level': 1, 'msg': 1,}
proj = {'_id': 1, 'level': 1, 'msg': 1}
limit = options['limit']
return self.collection.aggregate([
{"$match": query},
Expand Down
Loading