Отчеты об ошибках с гибкой средой App Engine

У меня возникают проблемы с работой отчетов об ошибках Google Stackdriver с использованием гибкой среды App Engine с Python 2.7.

В документации говорится, что гибкая среда требует ручной настройки: https://cloud.google.com/error-reporting/docs/setting-up-on-app-engine

По умолчанию со средой выполнения python похоже, что google-fluentd установлен, потому что ps ax | grep fluentd возвращает то, что предлагает документация. Однако выполнить sudo service google-fluentd restart не удается.

У меня есть fluent-logger==0.4.1 в моем файле requirements.txt.

Я переключился на пользовательскую среду выполнения, чтобы иметь возможность поместить файл forward.conf в /etc/google-fluentd/config.d, где предлагается документация.

Мой файл Docker выглядит так:

FROM gcr.io/google_appengine/python
RUN virtualenv /env -p python2.7

# stackdriver logging (for error reporting)
RUN mkdir -p /etc/google-fluentd/config.d
ADD forward.conf /etc/google-fluentd/config.d/    

# Set virtualenv environment variables. This is equivalent to running
# source /env/bin/activate
ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH
ADD requirements.txt /app/
RUN pip install --upgrade pip
RUN pip install -r requirements.txt

ADD . /app/
RUN python manage.py collectstatic --noinput
RUN python manage.py migrate --noinput

CMD gunicorn -b :$PORT project_name.wsgi

и forward.conf выглядит так:

<source>
  type forward
  port 24224
</source>

В моем приложении у меня есть представление, которое должно сообщать об ошибке, но ничего не происходит:

from django.http import HttpResponse
from django.views.generic import View

from fluent import sender
from fluent import event
import traceback

sender.setup('myapp', host='localhost', port=24224)


def report(ex):
    data = {}
    data['message'] = '{0}'.format(ex)
    data['serviceContext'] = {'service' : 'myapp'}
    # ... add more metadata
    event.Event('errors', data)


class ErrorView(View):

    def get(self, request, *args, **kwargs):
        # report exception data using:
        try:
            Exception("Woops.. an Error Occurred")
        except Exception as e:
            report(traceback.format_exc())
            raise e

Есть ли что-то, что мне не хватает в настройке? Журналы доступа к веб-серверу проходят нормально, но без исключений или записи в stderr или stdout.

Обновление от 09.05.2016

Благодаря ответу @Steren ... это намного проще, чем я понял, чтобы быть с Django в гибкой среде Python. Нет необходимости в пользовательской среде выполнения и установке fluentd. Ниже приведен рабочий пример, который выводит файл журнала в /var/log/app_engine/custom_logs/error.log и средство форматирования журнала, чтобы поместить журнал в соответствующий формат.

РЕГИСТРАЦИЯ Настройки:

    'formatters': {
        'gcp_json': {
            '()': 'helloworld.gcp_logger.GCPJsonFormatter',
        },
    },
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/var/log/app_engine/custom_logs/errors.json',
            'formatter': 'gcp_json',
        },
    },
    'loggers': {
        'django.request': {
            'filters': ['require_debug_false'],
            'handlers': ['file'],
            'level': 'ERROR',
            'propagate': True,
        },
    },

и форматер:

    import logging
    import json
    import os


    class GCPJsonFormatter(logging.Formatter):

        def format(self, record):
            # https://cloud.google.com/error-reporting/docs/formatting-error-messages
            return json.dumps({
                'eventTime': record.created,
                'message': self.formatException(record.exc_info),
                'level': record.levelname,
                'serviceContext': {


          'service': os.environ.get('GAE_MODULE_NAME', ''),
                'version': os.environ.get('GAE_MODULE_VERSION', ''),
            },
            "context": {
                "httpRequest": self._get_request_info(record),
                'user': str(record.request.user) if record.request else "",
                "reportLocation": {
                    "filePath": record.pathname,
                    "lineNumber": record.lineno,
                    "functionName": record.funcName,
                },
            }
        })

    def _get_request_info(self, record):
        try:
            request = record.request
            return {
                "method": request.method,
                "url": request.get_full_path(),
                "userAgent": request.META.get("HTTP_USER_AGENT", ""),
                "referrer": request.META.get("HTTP_REFERER", ""),
                "responseStatusCode": record.status_code,
                "remoteIp": request.META.get("REMOTE_ADDR", "")
            }
        except Exception:
            return {}

person Aaron    schedule 29.04.2016    source источник
comment
Привет, Аарон! Я менеджер продукта Stackdriver Error Reporting. Можете ли вы подтвердить, что видите сообщения об ошибках в средстве просмотра журналов как структурированную полезную нагрузку? Если да, то как называется поток журналов?   -  person Steren    schedule 03.05.2016
comment
Привет @Steren Я вижу журналы доступа в средстве просмотра журналов, но ошибки не отображаются в средстве просмотра журналов, как в стандартной среде. Стандартная среда показывает фрагмент трассировки стека (и все, что было записано в журнал), что действительно удобно.   -  person Aaron    schedule 03.05.2016
comment
Спасибо за ваш ответ. Да, действительно, гибкая среда не поддерживает журналы запросов, мы работаем над упрощением настройки отчетов об ошибках в гибкой среде. Видите ли вы трассировку стека в любом потоке журнала? Если нет, то это первый шаг. К следующей неделе я постараюсь опубликовать инструкции, чтобы заставить его работать на Node.js, они должны быть легко адаптированы для Python.   -  person Steren    schedule 04.05.2016
comment
@Steren - я не могу увидеть трассировку стека ни в одном из потоков журналов, в которые я не верю. Где я могу следить за вашими инструкциями по Node.js?   -  person Aaron    schedule 05.05.2016


Ответы (1)


Существует способ настроить гибкие среды выполнения App Engine, не требуя пользовательской среды выполнения. Вскоре он будет описан в официальной документации, и мы также работаем над тем, чтобы сделать эти шаги проще:

Вы должны использовать код, аналогичный описанному в . Примеры Google Compute Engine для отправки данных исключений в виде структурированных журналов в файл с именем /var/log/app_engine/custom_logs/errors.json (не отправляйте их через порт TCP)

Важно что:

  • Путь к файлу начинается с /var/log/app_engine/custom_logs/
  • Расширение файла .json
  • Имя файла содержит err в имени.
  • Файл содержит только структурированные объекты JSON.

Затем вы можете подтвердить в Stackdriver Logging, что вы видите ошибки, отображаемые как structPayload в пользовательском потоке журнала: выберите App Engine в первом раскрывающемся списке, а затем custom.var.lop.app_engine.app.custom_logs.errors.json.

Если это так, то отчет об ошибках должен автоматически начать обработку этих ошибок.

Дайте мне знать, если это не так.

person Steren    schedule 06.05.2016
comment
Спасибо, это очень полезно и позволяет мне увидеть ошибки в ведении журнала Stackdriver! Однако я до сих пор не вижу его в отчетах об ошибках. Требуется ли какое-то время для запуска или в структуре JSON мне может понадобиться другая структура? - person Aaron; 07.05.2016
comment
Я использую имя файла: /var/log/app_engine/custom_logs/errors.json Когда я подключаюсь к ящику по ssh, кажется, что журналы действительно расположены по адресу /var/log/app_engine/app/custom_logs/errors.json. - person Aaron; 08.05.2016
comment
Соответствует ли полезная нагрузка JSON той, что описана на этой странице: cloud.google. com/error-reporting/docs/formatting-error-messages. Поле сообщения должно содержать трассировку стека. - person Steren; 08.05.2016
comment
О, понял .. Я не понимал, что сообщение должно быть трассировкой стека. Работает фантастически. Большое спасибо за вашу помощь! - person Aaron; 09.05.2016