-
-
Notifications
You must be signed in to change notification settings - Fork 5
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
Unexpected logging behaviour #92
Comments
Hi @dmeehan1968 thanks for your question,
// ...
const lambdaLayer = Layer.mergeAll(
IngestServiceParams.Default,
EventBridge.defaultLayer,
).pipe(Layer.provideMerge(Logger.minimumLogLevel(LogLevel.Info)))
// ... it is bc it should be applyed on Layer, not on Effect // ...
const lambdaLayer = Layer.mergeAll(
IngestServiceParams.Default,
EventBridge.defaultLayer,
).pipe(Layer.provideMerge(Logger.logFmt)) // or `Logger.structured`
// ... the ultimate example would be // ...
const lambdaLayer = Layer.mergeAll(
IngestServiceParams.Default,
EventBridge.defaultLayer,
).pipe(
Layer.provideMerge(Logger.logFmt),
Layer.provideMerge(Logger.minimumLogLevel(LogLevel.Info))
)
// ... |
@floydspace Thank you, that was helpful in clarifying the order. I hadn't realised that the Layer.provideMerge(Logger.replace(Logger.defaultLogger, Logger.logfmtLogger)), Specifying the log level as indicated does fix the issue of filtering out the Please could you provide an example of using the effect-aws Powertools logger, there is no example in the docs. A mystery, but at least I now seem to have some working output as desired. Thanks! |
actually it is the same like with effect built-in loggers import { DefaultPowerToolsLoggerLayer } from "@effect-aws/powertools-logger";
// ...
const lambdaLayer = Layer.mergeAll(
IngestServiceParams.Default,
EventBridge.defaultLayer,
).pipe(Layer.provideMerge(DefaultPowerToolsLoggerLayer))
// ...
that is indeed mystery, bc |
@floydspace Unfortunately this doesn't work, I get no output at all (same as my previous problem). const lambdaLayer = Layer.mergeAll(
IngestServiceParams.Default,
EventBridge.defaultLayer,
).pipe(
Layer.provideMerge(DefaultPowerToolsLoggerLayer),
)
export const handler = makeLambda(ingestServiceHandler, lambdaLayer) Regards the longer format using |
I realised that one reason why I wasn't getting log output with the power tools logger is that my lambda environment is setup with the powertools environment variables to control the log level, and it defaults to errors only. This allowed me to refine the creation of the layer, but confusingly there is a difference. Here, this creates the power tools logger and uses the environment log level to determine output. This works as expected when log level is info, and I see both the client log and my application log, both formatted as for powertools. const lambdaLayer = Layer.empty.pipe(
Layer.provideMerge(IngestServiceParams.Default),
Layer.provideMerge(EventBridge.defaultLayer),
Layer.provideMerge(DefaultPowerToolsLoggerLayer),
) However, this seems like it should be functionally equivalent to the following, which is less verbose, but leads to the client log being with the Effect defaultLogger, and the application log being in the powertools format. const lambdaLayer = Layer.mergeAll(
IngestServiceParams.Default,
EventBridge.defaultLayer,
DefaultPowerToolsLoggerLayer,
) I then realised that when using mergeAll, perhaps the order of evaluation is important, but this also leads to the event bridge log using the default logger. const lambdaLayer = Layer.mergeAll(
IngestServiceParams.Default,
DefaultPowerToolsLoggerLayer,
EventBridge.defaultLayer,
)
Looking again at the const lambdaLayer = Layer.empty.pipe(
Layer.provideMerge(IngestServiceParams.Default),
Layer.provideMerge(DefaultPowerToolsLoggerLayer),
Layer.provideMerge(EventBridge.defaultLayer),
) Clearly my understanding of Layer merging is inadequate, and I can't figure out why the outcome is different. The best I rationalise from it is that merged layers (flat) don't effect each other, but that the chain of layers created by Perhaps this could be documented more clearly in the examples, perhaps in the @effect-aws/powertools-logger examples. |
it is not functionally equivalent, bc Layer.mergeAll(
IngestServiceParams.Default,
EventBridge.defaultLayer.pipe(Layer.provide(DefaultPowerToolsLoggerLayer)), // you need to provide for this layer separatly, bc the next line is just a sibling
DefaultPowerToolsLoggerLayer,
) so the correct way is using |
Ok, thanks. It's still not particularly clear to me and the examples in the effect.website don't really make it any clearer. A practical example in the docs for effect-aws (perhaps in the powertools logger service at least) would make this more apparent. At least for now I have a working example and can move on. Thank you very much for your advice. |
Related question: Is it possible to set a log level per layer? During development I would like to set the log level for AWS to warnings, but keep my business code info logs. |
does it work if you provide Layer.mergeAll(
IngestServiceParams.Default,
EventBridge.defaultLayer.pipe(Layer.provide(Logger.minimumLogLevel(LogLevel.Debug))),
DefaultPowerToolsLoggerLayer,
) |
I'm still struggling with dependency order when listed in the
This
The sub-services don't specify the PowerTools logger. In the dependencies: [
DeviceRepository.Default,
PayloadPublishingService.Default,
DefaultPowerToolsLoggerLayer,
] When I do this, I get the the default logger for the DecoderService, and PowerTools for the Dynamo and EventBridge services: dependencies: [
DeviceRepository.Default.pipe(Layer.provide(DefaultPowerToolsLoggerLayer)),
PayloadPublishingService.Default.pipe(Layer.provide(DefaultPowerToolsLoggerLayer)),
DefaultPowerToolsLoggerLayer,
] And when I do this, I get the same: dependencies: [
Layer.empty.pipe(
Layer.provideMerge(DeviceRepository.Default),
Layer.provideMerge(PayloadPublishingService.Default),
Layer.provideMerge(DefaultPowerToolsLoggerLayer),
),
] And when I do the following and apply the PowerTools layer to the DecoderService layer (outside of the Service, where its passed to the dependencies: [
DeviceRepository.Default,
PayloadPublishingService.Default,
] Within a unit test, I setup a layer as follows, and this gives PowerTools output for the DecoderService, and if I put log calls in the repository or publisher (the Dynamo and EventBridge clients are mocked, so there will be no output for those. const layer = DecoderService.DefaultWithoutDependencies.pipe(
Layer.provide(DeviceRepository.Default),
Layer.provide(PayloadPublishingService.Default),
Layer.provide(Layer.setConfigProvider(configProvider)),
Layer.provide(DefaultPowerToolsLoggerLayer),
)
const sut = () => DecoderService.handler.pipe(
Effect.andThen(handler => handler(event, {} as Context)),
Effect.provide(layer),
Effect.runPromise,
) Constructing the test layer like this also gives PowerTools log output from the DecoderService: const layer = DecoderService.Default.pipe(
Layer.provide(Layer.setConfigProvider(configProvider)),
Layer.provide(DefaultPowerToolsLoggerLayer),
) The difference in how layers are apparently constructed when using Effect.Service, at least when there is some nesting of the dependencies, seems to be different to constructing the layer by hand (no merging needed). It's very frustrating and I can't see any logic to it. I can't figure out if this is my failing, Effect.Service or the way the PowerToolsLoggerService is implemented. But I sure would like too! |
Aaah, the benefit of writing things out. In my export const handler = DecoderService.makeHandler() And the definition of that function was: static makeHandler(serviceLayer: Layer.Layer<DecoderService, ConfigError.ConfigError> = DecoderService.Default) {
const service = DecoderService.pipe(
Effect.provide(serviceLayer),
Effect.runSync,
)
return makeLambda(service.handler)
} Note that I was not passing the layer as the return makeLambda(service.handler, serviceLayer) I think this could be further refined as technically the globalLayer only needs the PowerTools layer, and not the other dependencies. The This also has the benefit of moving the PowerTools logger provision outside of the service, useful for services that might have different runtime contexts so the logger can be provided when needed. This makes the lambda handler initialisation this: export const handler = DecoderService.makeHandler(
DecoderService.Default.pipe(
Layer.provideMerge(DefaultPowerToolsLoggerLayer),
)
) I can then use the same interface to create the handler for testing purposes. For completeness, here is the outline of the DecoderService export class DecoderService extends Effect.Service<DecoderService>()('DecoderService', {
effect: Effect.gen(function* () {
const devices = yield* DeviceRepository
const events = yield* PayloadPublishingService
return {
handler: (unknown: unknown, _context: Context) => Effect.gen(function* () {
// Do event handling here
}),
}
}),
dependencies: [
DeviceRepository.Default,
PayloadPublishingService.Default,
],
}) {
static makeHandler(serviceLayer: Layer.Layer<DecoderService, ConfigError.ConfigError> = DecoderService.Default) {
const service = DecoderService.pipe(
Effect.provide(serviceLayer),
Effect.runSync,
)
return makeLambda(service.handler, serviceLayer)
}
} I think I got myself totally confused around layers and completely overlooked the relevance of providing the global layer. Of course, if this still isn't the right approach, I'm all ears! |
I'm relatively new to effect, and hoping to use it in my AWS projects. In attempting to write a lambda to handle incoming IoT Core Lorawan events, I seem to be struggling with logging.
There are two issues:
I have a feeling that I'm not setting up the environment correctly, possible related to the runtime that gets used. Any input gratefully received!
Context: we receive Lorawan data from IoT Core devices and external network services, and so the purpose of the code is to transform the events to a common event format and then publish them to EventBridge so that downstream microservices can handle them. In this case, this is receiving events from Loriot via its AWS IoT Core integration, so triggered by a Topic Rule.
The text was updated successfully, but these errors were encountered: