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

Cloud Logging: Documentation seems to be wrong regarding Authentication #4313

Open
JorgeSivil opened this issue Aug 2, 2021 · 1 comment
Labels
type: docs Improvement to the documentation for an API. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.

Comments

@JorgeSivil
Copy link

JorgeSivil commented Aug 2, 2021

Environment details

  • OS: Google Kubernetes Engine - phpfpm container
  • PHP version: 7.4
  • Package name and version: "google/cloud-logging": "^1.21"

Steps to reproduce

  1. Create a Kubernetes cluster
  2. Create an nginx + phpfpm pod
  3. Install the Cloud Logging library
  4. Produce an error
  5. You get the PERMISSION_DENIED response
{
	"error": {
		"code": 403,
		"message": "The caller does not have permission",
		"status": "PERMISSION_DENIED"
	}
}

Code example

<?php

namespace AppBundle\Monolog;

use Google\Cloud\Core\Report\SimpleMetadataProvider;
use Google\Cloud\Logging\LoggingClient;
use Monolog\Handler\PsrHandler;
use Monolog\Logger;
use Psr\Log\LoggerInterface;

class CloudLoggingHandler extends PsrHandler
{
  /**
   * @var LoggerInterface[]
   */
  protected $loggers;

  /**
   * @var LoggingClient
   */
  protected $client;

  /**
   * @var string
   */
  protected $name;

  /**
   * @var SimpleMetadataProvider
   */
  protected $metadata;

  /**
   * StackdriverHandler constructor.
   *
   * @param LoggerInterface $projectId
   * @param bool $name
   * @param bool|int $level
   * @param bool $bubble
   */
  public function __construct($projectId, $name, $level = Logger::WARNING, $bubble = false)
  {
    $this->client = new LoggingClient(
      [
        'projectId' => $projectId,
      ]
    );

    $this->name = $name;
    $this->level = $level;
    $this->bubble = $bubble;

    $this->metadata = new SimpleMetadataProvider([], $projectId, $name, '1');
  }

  private static function getFunctionNameForReport(array $trace = null)
  {
    if (null === $trace) {
      return '<unknown function>';
    }
    if (empty($trace[0]['function'])) {
      return '<none>';
    }
    $functionName = [$trace[0]['function']];
    if (isset($trace[0]['type'])) {
      $functionName[] = $trace[0]['type'];
    }
    if (isset($trace[0]['class'])) {
      $functionName[] = $trace[0]['class'];
    }
    return implode('', array_reverse($functionName));
  }

  /**
   * {@inheritdoc}
   * @throws \Exception
   */
  public function handle(array $record)
  {
    if (!$this->isHandling($record)) {
      return false;
    }

    if (isset($record['context']['exception'])
      && ($record['context']['exception'] instanceof \Exception || $record['context']['exception'] instanceof \Throwable))
    {
      $ex = $record['context']['exception'];
      $record['context']['reportLocation'] = [
        'filePath' => $ex->getFile(),
        'lineNumber' => $ex->getLine(),
        'functionName' => self::getFunctionNameForReport($ex->getTrace()),
      ];
    }

    $record['context']['serviceContext'] = [
      'service' => $this->name,
      'version' => 1
    ];

    if ($record['level'] >= Logger::ERROR) {
      $record['context']['@type'] = 'type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent';
    }

    $managed = true;
    try {
      $this->getLogger($record['channel'])->log(
        strtolower($record['level_name']),
        $record['message'],
        $record['context']
      );
    } catch (\Exception $e) {
      // Don't crash the app if Cloud Logging couldn't be authenticated (i.e. composer install)
      $managed = false;
    }

    return $managed;
  }

  /**
   * @param $channel
   *
   * @return LoggerInterface
   */
  protected function getLogger($channel)
  {
    if (!isset($this->loggers[$channel])) {
      $this->loggers[$channel] = $this->client->psrLogger(
        $this->name,
        [
          'labels' => ['context' => $channel],
          'metadataProvider' => $this->metadata,
        ]
      );
    }

    return $this->loggers[$channel];
  }
}

According to the docs in the readme, everything should work flawlessly. However it doesn't. And there's no further details on troubleshooting. I spent two or three days searching for solutions, and couldn't find one. In particular, there's no GOOGLE_CLOUD_PROJECT environment variable set in my containers. I set those parameters manually nevertheless, but I get the permission denied message.

It looks that, at least for Kubernetes, Cloud Logging does not work out of the box using the API from within GKE.

I added roles to the default service account however nothing changed:

image

image

I tried sending the errors to stderr which is supposedly the norm. My text line would get recognized as jsonPayload however Cloud Logging will ignore everything inside like '@type' and 'logName' for example. So in the end it doesn't work as one would thing it should, and errors are not sent to Error Reporting automatically due to this.

I had to come back to Cloud Logging API and tried re reading everything but didn't help. I'm so frustrated with documentation saying everywhere that things work out of the box but then they don't. I don't know what to do.

@JorgeSivil JorgeSivil changed the title Documentation seems to be wrong regarding Authentication Cloud Logging: Documentation seems to be wrong regarding Authentication Aug 2, 2021
@JorgeSivil
Copy link
Author

JorgeSivil commented Aug 2, 2021

For whoever is having this problem, follow this guide:

https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity

You need to create a service account, bind it to the deployment (https://stackoverflow.com/questions/44505461/how-to-configure-a-non-default-serviceaccount-on-a-deployment) and assign the service account the role "Logging Admin"

Probably this should be added to the guide.

@JorgeSivil JorgeSivil reopened this Aug 2, 2021
@yoshi-automation yoshi-automation added the triage me I really want to be triaged. label Aug 4, 2021
@dwsupplee dwsupplee added type: docs Improvement to the documentation for an API. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design. and removed triage me I really want to be triaged. labels Aug 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: docs Improvement to the documentation for an API. type: feature request ‘Nice-to-have’ improvement, new feature or different behavior or design.
Projects
None yet
Development

No branches or pull requests

3 participants