从 sbt 插件登录 [英] Logging from an sbt plugin

查看:38
本文介绍了从 sbt 插件登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 s3 解析器插件.

我已更改凭据提供程序:

I have changed the credentials provider:

lazy val s3CredentialsProvider = {bucket: String =>
    new AWSCredentialsProviderChain(
      new EnvironmentVariableCredentialsProvider(),
      PropertyFilesCredentialProvider.create(bucket)
    )
  }

其中 PropertyFilesCredentialProvider 是自定义提供程序.

where the PropertyFilesCredentialProvider is a custom provider.

我在以下位置执行了以下操作:

I have done the following where:

  • 我们使用 sbt.util.internal

我们添加了一个 System.out.println

相反.

我已经发布了该插件并且一直在另一个插件中使用它.看起来我的插件正在被使用,因为解析器每次都尝试使用不同的访问密钥,但我们看不到我们班级的日志.

I've published the plugin and have been using it in another plugin. It looks like my plugin is being used because the resolver attempts to use a different access key each time but we cannot see the logs from our class.

如果AutoPlugin中有代码,我们如何添加logging?

How can we add logging when we have code in an AutoPlugin?

Provider 的代码如下所示:

The code for the Provider looks like this:

import java.io.{File, FileInputStream, InputStream}导入 java.util.Properties

import java.io.{File, FileInputStream, InputStream} import java.util.Properties

import com.amazonaws.auth.{AWSCredentials, AWSCredentialsProvider, BasicSessionCredentials}
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder
import com.amazonaws.services.securitytoken.model.{AssumeRoleRequest, AssumeRoleResult, Credentials}

/** Creates a credential provider that reads a `roleArn` property from a file
  * and assumes the role using STS.
  *
  * This is based on https://github.com/frugalmechanic/fm-sbt-s3-resolver/blob/master/src/main/scala/fm/sbt/S3URLHandler.scala#L84
  *
  * @param file Properties file holding the ROLE_ARN for the project.
  */
class PropertyFilesCredentialProvider(file: File)
  extends AWSCredentialsProvider {

  private val ROLE_ARN_KEY: String = "roleArn"
  private val AWS_REGION: String = "<AWS_REGION>"

  protected def getRoleArn: String = {
    val is: InputStream = new FileInputStream(file)
    try {
      val props: Properties = new Properties()
      props.load(is)
      props.getProperty(ROLE_ARN_KEY)
    } finally is.close()
  }

  def createAWSCredentials(credentials: Credentials): AWSCredentials = {
    System.out.println("Retrieved AWS Session Token and Credentials for assuming role")
    new BasicSessionCredentials(credentials.getAccessKeyId,
      credentials.getSecretAccessKey,
      credentials.getSessionToken)
  }

  def assumeRole(roleArn: String): AssumeRoleResult = {
    System.out.println(s"Making a request to AWS STS with the roleArn: $roleArn to assume a role")
    val stsClient = AWSSecurityTokenServiceClientBuilder
      .standard
      .withRegion(AWS_REGION)
      .build

    val assumeRoleRequest = new AssumeRoleRequest
    assumeRoleRequest.setRoleArn(roleArn)
    stsClient.assumeRole(assumeRoleRequest)
  }

  override def getCredentials: AWSCredentials = {
    val roleArn = getRoleArn
    if (roleArn == null || roleArn == "") {
      System.out.println(s"Key of name $ROLE_ARN_KEY was not found in file at ${file.getAbsolutePath}")
      return null
    }
    System.out.println(s"$ROLE_ARN_KEY was read from ${file.getAbsolutePath} successfully")
    val assumeRoleResult = assumeRole(roleArn)
    System.out.println("Request to assume role using AWS STS successful")
    createAWSCredentials(assumeRoleResult.getCredentials)
  }

  override def refresh(): Unit = {}
}

object PropertyFilesCredentialProvider {

  private val DOT_SBT_DIR: File =
    new File(System.getProperty("user.home"), ".sbt")

  /** Uses a bucket specific propertyfile to read AWS `roleArn` from and provides it
    * to the PropertyFilesCredentialProvider.
    *
    * @param bucket Name of the S3 bucket.
    * @return a PropertyFileCredentialProvider
    */
  def create(bucket: String): PropertyFilesCredentialProvider = {
    val fileName = s".${bucket}_s3credentials"
    System.out.println("Using the Property Files Credential Provider")
    System.out.println(s"Reading $fileName for AWS Credentials ")
    val file: File = new File(DOT_SBT_DIR, fileName)
    new PropertyFilesCredentialProvider(file)
  }
}

更新

尝试使用 streams.value.log 失败并出现错误:

Attempts to use streams.value.log failed with the error:

`value` can only be called on a task within a task definition macro, 
 such as :=, +=, ++=, or Def.task.
[error]   val logger = streams.value.log
[error]   

尝试使用 ConsoleLogger,它是 Logger 的子类,但在类中实例化.其上的 apply 方法是这样调用的:

Attempts to use ConsoleLogger which is a sub class of Logger but instantiated within the class. The apply method on it was invoked like this:

val logger = sbt.internal.util.ConsoleLogger(System.out)
logger.info("s"Key of name $ROLE_ARN_KEY was not found in file at ${file.getAbsolutePath}"")

在上面的类中.那也没有输出日志.

inside the class above. That did not output the logs either.

我创建了两个记录器,一个用于类,另一个用于作为成员的伴随对象,而不是在扩展 AutoPlugin 的类中.

I created two loggers, one for the class and another for the companion object as members and not within the class extending AutoPlugin.

推荐答案

这是一种向您为 AutoPlugin 定义的类添加日志记录的方法

This is a way of adding logging to classes that you defined for your AutoPlugin

import sbt._
import sbt.Keys._

object TestPlugin extends AutoPlugin {

  class SomeClassThatNeedsLogger(logger: Logger) {
    def doSomeLogging(): Unit = {
      logger.info("It logs")
    }
  }

  object autoImport {
    val someClassThatNeedsLoggerHolder = taskKey[SomeClassThatNeedsLogger]("Holds instance of SomeClassThatNeedsLogger")
    val runSomeClassThatNeedsLogger = taskKey[Unit]("Runs SomeClassThatNeedsLogger")
  }

  import autoImport._

  override def trigger = allRequirements

  override def projectSettings: Seq[Def.Setting[_]] = {
    Seq(
      someClassThatNeedsLoggerHolder := new SomeClassThatNeedsLogger(streams.value.log),
      runSomeClassThatNeedsLogger := someClassThatNeedsLoggerHolder.value.doSomeLogging()
    )
  }
}

并且运行会给我们一个日志条目:

And running gives us a log entry:

> runSomeClassThatNeedsLogger
[info] It logs
[success] Total time: 0 s, completed Feb 6, 2019 9:47:15 AM

关于您遇到的错误的一些说明

Some notes on errors you're getting

value 只能在任务定义宏中的任务上调用,
例如:=、+=、++= 或 Def.task.

value can only be called on a task within a task definition macro,
such as :=, +=, ++=, or Def.task.

这告诉您 streams.value 只能在任务定义中使用,例如 someClassThatNeedsLoggerHolder := new SomeClassThatNeedsLogger(streams.value.log)

This tells you that streams.value can be used only in task definitions like someClassThatNeedsLoggerHolder := new SomeClassThatNeedsLogger(streams.value.log)

ConsoleLogger 使用 sbt.util.internal

ConsoleLogger using sbt.util.internal

顾名思义,这是一个内部包,可能会在下一版本的 sbt 中发生变化.不应在您的插件定义中使用它.

As the package name suggests, this is an internal package and subject to a change in next versions of sbt. It should not be used in your plugin definitions.

这篇关于从 sbt 插件登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆