title: Error Reporting with App Engine Flexible Environment
body: <p>I'm having troubles getting the Google Stackdriver Error Reporting to work using an App Engine Flexible Environment w/ Python 2.7</p>
  
  <p>The documentation says a flexible environment requires manual configuration: <a href="https://cloud.google.com/error-reporting/docs/setting-up-on-app-engine" rel="nofollow">https://cloud.google.com/error-reporting/docs/setting-up-on-app-engine</a></p>
  
  <p>By default with the python runtime, it looks like google-fluentd is installed because <code>ps ax | grep fluentd</code> returns what the docs suggest. However, doing a <code>sudo service google-fluentd restart</code> fails.</p>
  
  <p>I have <code>fluent-logger==0.4.1</code> in my requirements.txt file.</p>
  
  <p>I switched to a custom runtime to be able to place the <code>forward.conf</code> file in <code>/etc/google-fluentd/config.d</code> where the docs suggest.</p>
  
  <p>My Docker file looks like this:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>and forward.conf looks like:</p>
  
  <pre><code>&lt;source&gt;
    type forward
    port 24224
  &lt;/source&gt;
  </code></pre>
  
  <p>In my app I have a view that should report the error, but nothing comes through:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>Is there something I'm missing with the setup? The web server access logs come through just fine, but not exceptions or writing out to stderr or stdout</p>
  
  <h2>Update 5/9/2016</h2>
  
  <p>Thanks to @Steren's answer... it is much simpler than I made it out to be with Django in the Python Flexible Environment. There is no need for a custom runtime and installing <code>fluentd</code>. Below is a working sample that outputs a file log to <code>/var/log/app_engine/custom_logs/error.log</code> and a log formatter to put the log in the appropriate format. </p>
  
  <p>LOGGING Settings:</p>
  
  <pre><code>    '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,
          },
      },
  </code></pre>
  
  <p>and the formatter: </p>
  
  <pre><code>    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 {}
  </code></pre>