Skip to content

Commit

Permalink
Merge pull request #32 from agorapulse/feature/logging-function-initi…
Browse files Browse the repository at this point in the history
…alizer

Logging Function Initializer
  • Loading branch information
musketyr committed Jun 27, 2022
2 parents a0ee559 + 5a788f6 commit cfacba0
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 1 deletion.
13 changes: 12 additions & 1 deletion docs/guide/src/docs/asciidoc/usage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ Sentry events are enriched with the following information if available:
* `req.parameters`
* `req.headers`

== Ensure Exception Being Logged with @LogError
== Ensure Exception Being Logged

=== Using @LogError

All the errors have to be logged to be propagated to Sentry. You can use `LogErrors` around advice
with your entry-point method to simplify the logging boilerplate:
Expand Down Expand Up @@ -61,3 +63,12 @@ class ReportsService implements RequestHandler<SQSEvent, Void> {
----

WARNING: The annotation applied to the function class itself has no effect as the function class is executed by AWS Lambda container.

=== Using LoggingFunctionInitializer

You can extend `LoggingFunctionInitializer` instead of `FunctionInitializer` to ensure the problems with function initialization are logged.

=== Using Logging Request Handlers

Yuu can extend either `LoggingRequestHandler` or `LoggingRequestStreamHandler` to ensure the error is logged from the `handleRequest` methods.
You can use `LoggingFunction` and `LoggingConsumer` in case of using the interfaces from `java.util.function` package instead of AWS specific ones.
1 change: 1 addition & 0 deletions subprojects/micronaut-log4aws/micronaut-log4aws.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies {

implementation "io.micronaut:micronaut-core"

compileOnly 'io.micronaut:micronaut-function'
compileOnly 'io.micronaut:micronaut-http'
implementation 'io.micronaut:micronaut-aop'
implementation 'io.reactivex.rxjava2:rxjava'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2022 Agorapulse.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agorapulse.micronaut.log4aws.function;

import io.sentry.Sentry;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Callable;

public class Logging {

public static void runAndRethrow(Class<?> referenceClass, String message, Runnable action) {
try {
action.run();
} catch (Exception e) {
LoggerFactory.getLogger(referenceClass).error(message, e);
Sentry.flush(1000);
throw new IllegalStateException(message, e);
}
}

public static <T> T callAndRethrow(Class<?> referenceClass, String message, Callable<T> action) {
try {
return action.call();
} catch (Exception e) {
LoggerFactory.getLogger(referenceClass).error(message, e);
Sentry.flush(1000);
throw new IllegalStateException(message, e);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2022 Agorapulse.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agorapulse.micronaut.log4aws.function;

import java.util.function.Consumer;

public interface LoggingConsumer<T> extends Consumer<T> {

default void accept(T t) {
Logging.runAndRethrow(getClass(), "Exception running handler", () -> doAccept(t));
}

void doAccept(T t);


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2022 Agorapulse.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agorapulse.micronaut.log4aws.function;

import java.util.function.Function;

public interface LoggingFunction<T, R> extends Function<T, R> {

default R apply(T t) {
return Logging.callAndRethrow(getClass(), "Exception running handler", () -> doApply(t));
}

R doApply(T t);


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2022 Agorapulse.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agorapulse.micronaut.log4aws.function;

import io.micronaut.context.ApplicationContext;
import io.micronaut.function.executor.FunctionInitializer;

public class LoggingFunctionInitializer extends FunctionInitializer {

public LoggingFunctionInitializer() {
// for AWS startup
super();
}

public LoggingFunctionInitializer(ApplicationContext applicationContext) {
super(applicationContext);
}

public LoggingFunctionInitializer(ApplicationContext applicationContext, boolean inject) {
super(applicationContext, inject);
}

@Override
protected void startThis(ApplicationContext applicationContext) {
Logging.runAndRethrow(getClass(), "Exception starting the application context", () -> super.startThis(applicationContext));
}

@Override
@SuppressWarnings("unchecked")
protected ApplicationContext buildApplicationContext(Object context) {
return Logging.callAndRethrow(getClass(), "Exception building the application context", () -> super.buildApplicationContext(context));
}

@Override
protected void injectThis(ApplicationContext applicationContext) {
Logging.runAndRethrow(getClass(), "Exception injecting the function handler", () -> super.injectThis(applicationContext));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2022 Agorapulse.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agorapulse.micronaut.log4aws.function;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public interface LoggingRequestHandler<I, O> extends RequestHandler<I, O> {

default O handleRequest(I input, Context context) {
return Logging.callAndRethrow(getClass(), "Exception running handler", () -> doHandleRequest(input, context));
}

O doHandleRequest(I input, Context context);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2022 Agorapulse.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agorapulse.micronaut.log4aws.function;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;

import java.io.InputStream;
import java.io.OutputStream;

public interface LoggingRequestStreamHandler extends RequestStreamHandler {

default void handleRequest(InputStream input, OutputStream output, Context context) {
Logging.runAndRethrow(getClass(), "Exception running handler", () -> doHandleRequest(input, output, context));
}

<T> T doHandleRequest(InputStream input, OutputStream output, Context context);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright 2020-2022 Agorapulse.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.agorapulse.micronaut.log4aws.function

import com.amazonaws.services.lambda.runtime.Context
import groovy.transform.CompileStatic
import spock.lang.Specification

class LoggingSpec extends Specification {

void 'consumer test'() {
when:
new TestConsumer().accept('something')
then:
thrown(IllegalStateException)
}

void 'function test'() {
when:
new TestFunction().apply('something')
then:
thrown(IllegalStateException)
}

void 'request handler test'() {
when:
new TestRequestHandler().handleRequest('something', Mock(Context))
then:
thrown(IllegalStateException)
}

void 'request stream handler test'() {
when:
new TestRequestStreamHandler().handleRequest(Mock(InputStream), Mock(OutputStream), Mock(Context))
then:
thrown(IllegalStateException)
}

}

@CompileStatic
class TestConsumer implements LoggingConsumer<String> {

@Override
void doAccept(String s) {
throw new UnsupportedOperationException('not implemented')
}

}

@CompileStatic
class TestFunction implements LoggingFunction<String, String> {

@Override
String doApply(String s) {
throw new UnsupportedOperationException('not implemented')
}

}

@CompileStatic
class TestRequestHandler implements LoggingRequestHandler<String, String> {

@Override
String doHandleRequest(String input, Context context) {
throw new UnsupportedOperationException('not implemented')
}

}

@CompileStatic
class TestRequestStreamHandler implements LoggingRequestStreamHandler {

@Override
public <T> T doHandleRequest(InputStream input, OutputStream output, Context context) {
throw new UnsupportedOperationException('not implemented')
}

}

0 comments on commit cfacba0

Please sign in to comment.