From 5d98792d09e78b7f1a3ecdaba458a0c3c74a0faf Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Sun, 7 Apr 2019 22:57:28 +0200 Subject: Add the `LogEntry` model. --- .../api/migrations/0035_create_table_log_entry.py | 28 +++++++++++++++ pydis_site/apps/api/models.py | 42 ++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 pydis_site/apps/api/migrations/0035_create_table_log_entry.py (limited to 'pydis_site') diff --git a/pydis_site/apps/api/migrations/0035_create_table_log_entry.py b/pydis_site/apps/api/migrations/0035_create_table_log_entry.py new file mode 100644 index 00000000..30ff1ffd --- /dev/null +++ b/pydis_site/apps/api/migrations/0035_create_table_log_entry.py @@ -0,0 +1,28 @@ +# Generated by Django 2.1.5 on 2019-04-07 20:53 + +from django.db import migrations, models +import django.utils.timezone +import pydis_site.apps.api.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0034_add_botsetting_name_validator'), + ] + + operations = [ + migrations.CreateModel( + name='LogEntry', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('application', models.CharField(choices=[('bot', 'Bot'), ('seasonalbot', 'Seasonalbot'), ('site', 'Website')], help_text='The application that generated this log entry.', max_length=20)), + ('logger_name', models.CharField(help_text='The name of the logger that generated this log entry.', max_length=100)), + ('timestamp', models.DateTimeField(default=django.utils.timezone.now, help_text='The date and time when this entry was created.')), + ('level', models.CharField(choices=[('debug', 'Debug'), ('info', 'Info'), ('warning', 'Warning'), ('error', 'Error'), ('critical', 'Critical')], help_text='The logger level at which this entry was emitted. The levels correspond to the Python `logging` levels.', max_length=8)), + ('module', models.CharField(help_text='The fully qualified path of the module generating this log line.', max_length=100)), + ('line', models.PositiveSmallIntegerField(help_text='The line at which the log line was emitted.')), + ], + bases=(pydis_site.apps.api.models.ModelReprMixin, models.Model), + ), + ] diff --git a/pydis_site/apps/api/models.py b/pydis_site/apps/api/models.py index 86c99f86..a541e4ab 100644 --- a/pydis_site/apps/api/models.py +++ b/pydis_site/apps/api/models.py @@ -450,3 +450,45 @@ class Nomination(ModelReprMixin, models.Model): auto_now_add=True, help_text="The creation date of this nomination." ) + +class LogEntry(ModelReprMixin, models.Model): + """A log entry generated by one of the PyDis applications.""" + + application = models.CharField( + max_length=20, + help_text="The application that generated this log entry.", + choices=( + ('bot', 'Bot'), + ('seasonalbot', 'Seasonalbot'), + ('site', 'Website') + ) + ) + logger_name = models.CharField( + max_length=100, + help_text="The name of the logger that generated this log entry." + ) + timestamp = models.DateTimeField( + default=timezone.now, + help_text="The date and time when this entry was created." + ) + level = models.CharField( + max_length=8, # 'critical' + choices=( + ('debug', 'Debug'), + ('info', 'Info'), + ('warning', 'Warning'), + ('error', 'Error'), + ('critical', 'Critical') + ), + help_text=( + "The logger level at which this entry was emitted. The levels " + "correspond to the Python `logging` levels." + ) + ) + module = models.CharField( + max_length=100, + help_text="The fully qualified path of the module generating this log line." + ) + line = models.PositiveSmallIntegerField( + help_text="The line at which the log line was emitted." + ) -- cgit v1.2.3 From 5006641ce1527524e85f22c9b4dc0096fe2718b9 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Sun, 7 Apr 2019 23:32:19 +0200 Subject: Add the `/logs` API route. --- pydis_site/apps/api/serializers.py | 21 +++++++++++++++------ pydis_site/apps/api/urls.py | 12 +++++++----- pydis_site/apps/api/viewsets.py | 31 +++++++++++++++++++------------ 3 files changed, 41 insertions(+), 23 deletions(-) (limited to 'pydis_site') diff --git a/pydis_site/apps/api/serializers.py b/pydis_site/apps/api/serializers.py index 9a92313a..2b0a687f 100644 --- a/pydis_site/apps/api/serializers.py +++ b/pydis_site/apps/api/serializers.py @@ -5,12 +5,12 @@ from rest_framework_bulk import BulkSerializerMixin from .models import ( BotSetting, DeletedMessage, DocumentationLink, Infraction, - MessageDeletionContext, Nomination, - OffTopicChannelName, Reminder, - Role, SnakeFact, - SnakeIdiom, SnakeName, - SpecialSnake, Tag, - User + LogEntry, MessageDeletionContext, + Nomination, OffTopicChannelName, + Reminder, Role, + SnakeFact, SnakeIdiom, + SnakeName, SpecialSnake, + Tag, User ) @@ -102,6 +102,15 @@ class ExpandedInfractionSerializer(InfractionSerializer): return ret +class LogEntrySerializer(ModelSerializer): + class Meta: + model = LogEntry + fields = ( + 'application', 'logger_name', 'timestamp', + 'level', 'module', 'line' + ) + + class OffTopicChannelNameSerializer(ModelSerializer): class Meta: model = OffTopicChannelName diff --git a/pydis_site/apps/api/urls.py b/pydis_site/apps/api/urls.py index 6c89a52e..724d7e2b 100644 --- a/pydis_site/apps/api/urls.py +++ b/pydis_site/apps/api/urls.py @@ -5,11 +5,12 @@ from .views import HealthcheckView, RulesView from .viewsets import ( BotSettingViewSet, DeletedMessageViewSet, DocumentationLinkViewSet, InfractionViewSet, - NominationViewSet, OffTopicChannelNameViewSet, - ReminderViewSet, RoleViewSet, - SnakeFactViewSet, SnakeIdiomViewSet, - SnakeNameViewSet, SpecialSnakeViewSet, - TagViewSet, UserViewSet + LogEntryViewSet, NominationViewSet, + OffTopicChannelNameViewSet, ReminderViewSet, + RoleViewSet, SnakeFactViewSet, + SnakeIdiomViewSet, SnakeNameViewSet, + SpecialSnakeViewSet, TagViewSet, + UserViewSet ) @@ -81,6 +82,7 @@ urlpatterns = ( # from django_hosts.resolvers import reverse # snake_name_endpoint = reverse('bot:snakename-list', host='api') # `bot/` endpoints path('bot/', include((bot_router.urls, 'api'), namespace='bot')), + path('logs', LogEntryViewSet.as_view({'post': 'create'}), name='logs'), path('healthcheck', HealthcheckView.as_view(), name='healthcheck'), path('rules', RulesView.as_view(), name='rules') ) diff --git a/pydis_site/apps/api/viewsets.py b/pydis_site/apps/api/viewsets.py index 949ffaaa..b97f19b6 100644 --- a/pydis_site/apps/api/viewsets.py +++ b/pydis_site/apps/api/viewsets.py @@ -15,22 +15,23 @@ from rest_framework_bulk import BulkCreateModelMixin from .models import ( BotSetting, DocumentationLink, - Infraction, MessageDeletionContext, - Nomination, OffTopicChannelName, - Reminder, Role, - SnakeFact, SnakeIdiom, - SnakeName, SpecialSnake, - Tag, User + Infraction, LogEntry, + MessageDeletionContext, Nomination, + OffTopicChannelName, Reminder, + Role, SnakeFact, + SnakeIdiom, SnakeName, + SpecialSnake, Tag, + User ) from .serializers import ( BotSettingSerializer, DocumentationLinkSerializer, ExpandedInfractionSerializer, InfractionSerializer, - MessageDeletionContextSerializer, NominationSerializer, - OffTopicChannelNameSerializer, ReminderSerializer, - RoleSerializer, SnakeFactSerializer, - SnakeIdiomSerializer, SnakeNameSerializer, - SpecialSnakeSerializer, TagSerializer, - UserSerializer + LogEntrySerializer, MessageDeletionContextSerializer, + NominationSerializer, OffTopicChannelNameSerializer, + ReminderSerializer, RoleSerializer, + SnakeFactSerializer, SnakeIdiomSerializer, + SnakeNameSerializer, SpecialSnakeSerializer, + TagSerializer, UserSerializer ) @@ -280,6 +281,12 @@ class InfractionViewSet(CreateModelMixin, RetrieveModelMixin, ListModelMixin, Ge return self.partial_update(*args, **kwargs) +class LogEntryViewSet(CreateModelMixin, GenericViewSet): + # TODO: doc me foobar baz boom bang crow caw caw caw + queryset = LogEntry.objects.all() + serializer_class = LogEntrySerializer + + class OffTopicChannelNameViewSet(DestroyModelMixin, ViewSet): """ View of off-topic channel names used by the bot -- cgit v1.2.3 From 91294e94e1205ba32b12d0cebc899d1337583740 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Sun, 7 Apr 2019 23:34:42 +0200 Subject: Minor formatting improvements. --- pydis_site/apps/api/models.py | 1 + 1 file changed, 1 insertion(+) (limited to 'pydis_site') diff --git a/pydis_site/apps/api/models.py b/pydis_site/apps/api/models.py index a541e4ab..35b76c4c 100644 --- a/pydis_site/apps/api/models.py +++ b/pydis_site/apps/api/models.py @@ -451,6 +451,7 @@ class Nomination(ModelReprMixin, models.Model): help_text="The creation date of this nomination." ) + class LogEntry(ModelReprMixin, models.Model): """A log entry generated by one of the PyDis applications.""" -- cgit v1.2.3 From 2a4e5e606520fca4649b2a7c40e73e8380e4798d Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Mon, 8 Apr 2019 20:28:48 +0200 Subject: Add the `message` field. --- pydis_site/apps/api/migrations/0035_create_table_log_entry.py | 3 ++- pydis_site/apps/api/models.py | 3 +++ pydis_site/apps/api/serializers.py | 3 +-- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'pydis_site') diff --git a/pydis_site/apps/api/migrations/0035_create_table_log_entry.py b/pydis_site/apps/api/migrations/0035_create_table_log_entry.py index 30ff1ffd..a8256a0e 100644 --- a/pydis_site/apps/api/migrations/0035_create_table_log_entry.py +++ b/pydis_site/apps/api/migrations/0035_create_table_log_entry.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.5 on 2019-04-07 20:53 +# Generated by Django 2.1.5 on 2019-04-08 18:27 from django.db import migrations, models import django.utils.timezone @@ -22,6 +22,7 @@ class Migration(migrations.Migration): ('level', models.CharField(choices=[('debug', 'Debug'), ('info', 'Info'), ('warning', 'Warning'), ('error', 'Error'), ('critical', 'Critical')], help_text='The logger level at which this entry was emitted. The levels correspond to the Python `logging` levels.', max_length=8)), ('module', models.CharField(help_text='The fully qualified path of the module generating this log line.', max_length=100)), ('line', models.PositiveSmallIntegerField(help_text='The line at which the log line was emitted.')), + ('message', models.TextField(help_text='The textual content of the log line.')), ], bases=(pydis_site.apps.api.models.ModelReprMixin, models.Model), ), diff --git a/pydis_site/apps/api/models.py b/pydis_site/apps/api/models.py index 35b76c4c..b2499f8d 100644 --- a/pydis_site/apps/api/models.py +++ b/pydis_site/apps/api/models.py @@ -493,3 +493,6 @@ class LogEntry(ModelReprMixin, models.Model): line = models.PositiveSmallIntegerField( help_text="The line at which the log line was emitted." ) + message = models.TextField( + help_text="The textual content of the log line." + ) diff --git a/pydis_site/apps/api/serializers.py b/pydis_site/apps/api/serializers.py index 2b0a687f..8f045044 100644 --- a/pydis_site/apps/api/serializers.py +++ b/pydis_site/apps/api/serializers.py @@ -1,5 +1,4 @@ from rest_framework.serializers import ModelSerializer, PrimaryKeyRelatedField, ValidationError -from rest_framework.validators import UniqueValidator from rest_framework_bulk import BulkSerializerMixin from .models import ( @@ -107,7 +106,7 @@ class LogEntrySerializer(ModelSerializer): model = LogEntry fields = ( 'application', 'logger_name', 'timestamp', - 'level', 'module', 'line' + 'level', 'module', 'line', 'message' ) -- cgit v1.2.3 From e00b347ca513e83029110ef740657b2ecda028a2 Mon Sep 17 00:00:00 2001 From: Johannes Christ Date: Wed, 10 Apr 2019 19:50:32 +0200 Subject: Document `LogEntryViewSet`. --- pydis_site/apps/api/viewsets.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'pydis_site') diff --git a/pydis_site/apps/api/viewsets.py b/pydis_site/apps/api/viewsets.py index b97f19b6..47915256 100644 --- a/pydis_site/apps/api/viewsets.py +++ b/pydis_site/apps/api/viewsets.py @@ -282,7 +282,33 @@ class InfractionViewSet(CreateModelMixin, RetrieveModelMixin, ListModelMixin, Ge class LogEntryViewSet(CreateModelMixin, GenericViewSet): - # TODO: doc me foobar baz boom bang crow caw caw caw + """ + View providing support for creating log entries in the site database + for viewing via the log browser. + + ## Routes + ### POST /logs + Create a new log entry. + + #### Request body + >>> { + ... 'application': str, # 'bot' | 'seasonalbot' | 'site' + ... 'logger_name': str, # such as 'bot.cogs.moderation' + ... 'timestamp': Optional[str], # from `datetime.utcnow().isoformat()` + ... 'level': str, # 'debug' | 'info' | 'warning' | 'error' | 'critical' + ... 'module': str, # such as 'pydis_site.apps.api.serializers' + ... 'line': int, # > 0 + ... 'message': str, # textual formatted content of the logline + ... } + + #### Status codes + - 201: returned on success + - 400: if the request body has invalid fields, see the response for details + + ## Authentication + Requires a API token. + """ + queryset = LogEntry.objects.all() serializer_class = LogEntrySerializer -- cgit v1.2.3