从 sbt 插件记录 [英] Logging from an sbt plugin
问题描述
我为 sbt 使用 s3 解析器插件.
I use the s3 resolver plugin for sbt.
我已更改凭据提供程序:
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:
导入 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屋!