Stacked-Org/stacked

[feature]: Google Cloud Logging Output Target for Stacked Logger

Closed this issue · 3 comments

Is your feature request related to a problem? Please describe.

In this video https://youtu.be/pab8ZamcrIo?t=159 Dane mentions having a Google Cloud output target for the stacked logger. I was wondering if there is any source code or examples of how to implement this in stacked? I didn't see it in the docs anywhere.

Describe the solution you would like

Could you provide updates to the docs or point me in the direction of how to setup Google Cloud Logging using the Stacked Logger?

Additional Context

Stacked is awesome!

Hey, that's a good catch.

I do have an implementation but it's using the old StackDriver implementation.

Let me find it and share it with you here.

It's very basic.

Here's the stack driver service. I've redacted some of my creds:

import 'package:flutter/foundation.dart' as foundation;
import 'package:flutter/services.dart' show rootBundle;
import 'package:googleapis/logging/v2.dart';
import 'package:googleapis_auth/auth_io.dart';
import 'package:logger/logger.dart';

const _SCOPES = const ['https://www.googleapis.com/auth/logging.write'];

class StackDriverService {
  static late ServiceAccountCredentials _credentials;
  static StackDriverService? _instance;
  static late AutoRefreshingAuthClient _authClient;
  static late LoggingApi _loggingApi;
  var resource = new MonitoredResource()..type = 'global';

  final labels = <String, String>{
    'project_id': '<your-project-id-here>',
    'environment': foundation.kDebugMode ? 'Development' : 'Production'
  };

  static Future<StackDriverService> initialise() async {
    if (_instance != null) {
      return _instance!;
    }

    var credentialJson = await rootBundle.loadString(
      'assets/path-to-your-service-account.json',
    );

    _credentials = ServiceAccountCredentials.fromJson(credentialJson);
    _authClient = await clientViaServiceAccount(_credentials, _SCOPES);
    _loggingApi = LoggingApi(_authClient);
    print(
        'GoogleApiService setup successfully completed for stack driver logging');

    _instance = StackDriverService();
    return _instance!;
  }

  void writeEntry(Level level, List<String> lines) {
    if (_instance != null) {
      LogEntry logEntry = LogEntry();
      logEntry.logName = "projects/your-google-project-name";
      logEntry.jsonPayload = {'message': lines.join('\n')};
      logEntry.resource = resource;
      labels['level'] = level.toString();
      logEntry.labels = labels;

      var request = WriteLogEntriesRequest();
      request.entries = [logEntry];

      _loggingApi.entries.write(request).catchError((error) {
        print('Stackdriver write error');
      });
    }
  }

  void setUserId(String? uid) {
    labels['user_id'] = uid ?? 'UnknownUID';
  }
}

The logger output.

class GoogleCloudLoggerOutout extends LogOutput {
  @override
  void output(OutputEvent event) {
    if (!Platform.environment.containsKey('FLUTTER_TEST') &&
        locator.isRegistered<StackDriverService>()) {
      final loggerService = locator<StackDriverService>();
      loggerService.writeEntry(
        event.level,
        event.lines,
      );
    }
  }
}

The use with the Stacked logger.

Logger getLogger(
  String className, {
  bool printCallingFunctionName = true,
  bool printCallstack = false,
  List<String> exludeLogsFromClasses = const [],
  String? showOnlyClass,
}) {
  return Logger(
    printer: SimpleLogPrinter(
      className,
      printCallingFunctionName: printCallingFunctionName,
      printCallStack: printCallstack,
      showOnlyClass: showOnlyClass,
      exludeLogsFromClasses: exludeLogsFromClasses,
    ),
    output: MultipleLoggerOutput([
      FileOutput(),
      ConsoleOutput(),
      GoogleCloudLoggerOutout(),
    ]),
  );
}

You can ofcourse just pass in the log output to the StackedLogger in the app.dart file.

Awesome! Thanks!!