amazonka icon indicating copy to clipboard operation
amazonka copied to clipboard

Can't quietly handle exceptions

Open Fuuzetsu opened this issue 5 years ago • 2 comments

I have some simple code that checks if an image with a tag already exists in some ECR repository:

        AWS.trying ECR._ImageNotFoundException (AWS.send describeImages) >>= \case
            -- We failed with ImageNotFound, clearly the tag is not present.
            Left{} -> pure False
            -- We got some result, must be for image ID we passed.
            Right{} -> pure True

I'm using newLogger with Error :: LogLevel. Running this code, in the console I see:

[ServiceError] {
  service    = ECR
  status     = 400 Bad Request
  code       = ImageNotFound
  message    = Just The image with imageId {imageDigest:'null', imageTag:'SOMETAG'} does not exist within the repository with name 'some_repo' in the registry with id 'xxxxx'
  request-id = Just xxxxx
}
# output from rest of program

I don't see how I can handle ImageNotFoundException such that the warning is not printed: it's expected here. Creating new env with silent logger isn't great either: I still want to see any other exceptions that may occur, like connection errors and such.

Am I missing something obvious?

Fuuzetsu avatar May 28 '20 06:05 Fuuzetsu

I did something like this, which seems like too big of a hammer as it swallows everything:

            silently = local (\e -> e & AWS.envLogger .~ (\_ _ -> pure ()))

        -- If we get an ImageNotFound exception, clearly the image is
        -- not there. Otherwise, image is there.
        silently $ either (const False) (const True)
            <$> AWS.trying ECR._ImageNotFoundException (AWS.send describeImages)

Fuuzetsu avatar May 28 '20 06:05 Fuuzetsu

Yes, it appears that this is how you'd have to do it. Some things that might not be obvious with lens, but the type of AWS.envLogger .~ (\_ _ -> pure ()) is itself Env -> Env, so the \e -> e & part is redundant.

You can also use (%~) to modify the logging function instead of replacing it; this allows you to delegate to the original logger:

let wrapLogger :: Logger -> Logger
    wrapLogger oldLogger level builder = case level of
      Info -> oldLogger level builder
      _ -> pure ()

    silently = local $ AWS.envLogger %~ wrapLogger
in ...

Maybe it would be nicer if we passed structured data to the logging function, perhaps through a sum type of ByteStringBuilder | ServiceError | ..., and made available a rendering function ServiceError -> ByteString or something?

But this will be too much for 2.0.

endgame avatar Sep 29 '21 09:09 endgame

Should this be in the 2.0 Milestone still? It seems like the %~ wrapLogger workaround is a decent one, and doing something better would be "too much for 2.0".

pbrisbin avatar Oct 24 '22 15:10 pbrisbin

It's on my list to think about properly in the next couple of weeks.

endgame avatar Oct 24 '22 22:10 endgame