public function log($level, $message, array $context = [])
    {
        $this->validateLogLevel($level);
        $options = [];

        if (isset($context['exception'])
            && ($context['exception'] instanceof \Exception || $context['exception'] instanceof \Throwable)) {
            $context['exception'] = (string) $context['exception'];
        }

        if (isset($context['stackdriverOptions'])) {
            $options = $context['stackdriverOptions'];
            unset($context['stackdriverOptions']);
        }

        $formatter = new NormalizerFormatter();
        $processor = new PsrLogMessageProcessor();
        $processedData = $processor([
            'message' => (string) $message,
            'context' => $formatter->format($context)
        ]);
        $jsonPayload = [$this->messageKey => $processedData['message']];

        // Adding labels for log request correlation.
        $labels = $this->getLabels();
        if (!empty($labels)) {
            $options['labels'] =
                (isset($options['labels'])
                 ? $options['labels']
                 : []) + $labels;
            // Copy over the value for 'appengine.googleapis.com/trace_id' to
            // `trace` option too.
            if (isset($labels['appengine.googleapis.com/trace_id'])) {
                $options['trace'] =
                    $labels['appengine.googleapis.com/trace_id'];
            }
        }
        // Adding MonitoredResource
        $resource = $this->metadataProvider->monitoredResource();
        if (!empty($resource)) {
            $options['resource'] =
                (isset($options['resource'])
                 ? $options['resource']
                 : []) + $resource;
        }
        $entry = $this->logger->entry(
            $jsonPayload + $processedData['context'],
            $options + [
                'severity' => $level
            ]
        );
        $this->sendEntry($entry);
    }