Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ class GrailsUtilStackFiltererSpec extends Specification {
}

def 'installed DefaultStackTraceFilterer honours logFullStackTraceOnFilter=false'() {
given: 'a configured log appender to capture the StackTrace log entry'
def logCapture = new LogCapture('StackTrace')
given: 'a capture of the dedicated STACK_LOG logger'
def logCapture = new LogCapture(DefaultStackTraceFilterer.STACK_LOG_NAME)

and: 'a filterer with the side-effect emission disabled'
def quietFilterer = new DefaultStackTraceFilterer()
Expand All @@ -117,15 +117,15 @@ class GrailsUtilStackFiltererSpec extends Specification {
GrailsUtil.deepSanitize(exceptionWithApplicationFrame())

then: "no 'Full Stack Trace:' entry is emitted"
logCapture.events.count { it.formattedMessage.contains(StackTraceFilterer.FULL_STACK_TRACE_MESSAGE) } == 0
logCapture.events.every { !it.formattedMessage.contains(StackTraceFilterer.FULL_STACK_TRACE_MESSAGE) }

cleanup:
logCapture.close()
}

def 'installed DefaultStackTraceFilterer emits Full Stack Trace by default'() {
given: 'a configured log appender to capture the StackTrace log entry'
def logCapture = new LogCapture('StackTrace')
given: 'a capture of the dedicated STACK_LOG logger'
def logCapture = new LogCapture(DefaultStackTraceFilterer.STACK_LOG_NAME)

and: 'a filterer with the default (enabled) side-effect emission'
def loudFilterer = new DefaultStackTraceFilterer()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,14 @@ class GrailsBootstrapRegistryInitializerSpec extends Specification {
def context = contextWithProperties([
(Settings.SETTING_LOG_FULL_STACKTRACE_ON_FILTER): 'false'
])
def logCapture = new LogCapture('StackTrace')
def logCapture = new LogCapture(DefaultStackTraceFilterer.STACK_LOG_NAME)

when:
closeBootstrapContext(context)
GrailsUtil.deepSanitize(exceptionWithApplicationFrame())

then: "no 'Full Stack Trace:' entry is emitted"
logCapture.events.count { it.formattedMessage.contains(StackTraceFilterer.FULL_STACK_TRACE_MESSAGE) } == 0
logCapture.events.every { !it.formattedMessage.contains(StackTraceFilterer.FULL_STACK_TRACE_MESSAGE) }

cleanup:
logCapture.close()
Expand All @@ -242,7 +242,7 @@ class GrailsBootstrapRegistryInitializerSpec extends Specification {
def 'defaults logFullStackTraceOnFilter to true on the promoted DefaultStackTraceFilterer'() {
given:
def context = contextWithProperties([:])
def logCapture = new LogCapture('StackTrace')
def logCapture = new LogCapture(DefaultStackTraceFilterer.STACK_LOG_NAME)

when:
closeBootstrapContext(context)
Expand Down
2 changes: 1 addition & 1 deletion grails-web-mvc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ dependencies {
api 'org.slf4j:jcl-over-slf4j'

// Testing
testImplementation 'org.slf4j:slf4j-simple'
testImplementation(testFixtures(project(':grails-core')))
testImplementation 'org.spockframework:spock-core'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import grails.config.Config
import grails.core.GrailsApplication
import grails.web.mapping.UrlMappingsHolder
import grails.web.mapping.exceptions.UrlMappingException
import org.apache.grails.core.testing.support.LogCapture
import org.grails.exceptions.reporting.DefaultStackTraceFilterer
import org.apache.grails.core.GrailsBootstrapRegistryInitializer
import org.grails.exceptions.reporting.StackTraceFilterer
Expand Down Expand Up @@ -53,10 +54,9 @@ class GrailsExceptionResolverSpec extends Specification {
}

void "logStackTrace emits only the resolver log"() {
given: "Captured System.err"
def originalErr = System.err
def baos = new ByteArrayOutputStream()
System.setErr(new PrintStream(baos, true))
given: "captures of both the resolver logger and the StackTrace logger"
def resolverLog = new LogCapture(GrailsExceptionResolver)
def stackLog = new LogCapture(DefaultStackTraceFilterer.STACK_LOG_NAME)

and: "A resolver with no grailsApplication wired"
def resolver = new GrailsExceptionResolver()
Expand All @@ -67,21 +67,17 @@ class GrailsExceptionResolverSpec extends Specification {
resolver.logStackTrace(exception, request)

then: "Only the GrailsExceptionResolver logger emits; StackTrace logger is silent"
System.err.flush()
def captured = baos.toString()
captured.contains('o.g.web.errors.GrailsExceptionResolver') ||
captured.contains('org.grails.web.errors.GrailsExceptionResolver')
!captured.contains('ERROR StackTrace ')
resolverLog.events.any { it.loggerName == GrailsExceptionResolver.name }
stackLog.events.isEmpty()

cleanup:
System.setErr(originalErr)
resolverLog.close()
stackLog.close()
}

void "logFullStackTraceIfEnabled is a no-op when the opt-in property is unset"() {
given: "Captured System.err"
def originalErr = System.err
def baos = new ByteArrayOutputStream()
System.setErr(new PrintStream(baos, true))
given: "a capture of the StackTrace logger"
def stackLog = new LogCapture(DefaultStackTraceFilterer.STACK_LOG_NAME)

and: "A resolver with no grailsApplication wired"
def resolver = new GrailsExceptionResolver()
Expand All @@ -91,11 +87,10 @@ class GrailsExceptionResolverSpec extends Specification {
resolver.logFullStackTraceIfEnabled(exception)

then: "No StackTrace log entry is emitted"
System.err.flush()
!baos.toString().contains('ERROR StackTrace ')
stackLog.events.isEmpty()

cleanup:
System.setErr(originalErr)
stackLog.close()
}

void "getRequestLogMessage appends auditor when logAuditor is enabled and the lookup returns a value"() {
Expand Down Expand Up @@ -264,10 +259,9 @@ class GrailsExceptionResolverSpec extends Specification {
}

void "logFullStackTraceIfEnabled emits the unfiltered trace when opt-in is enabled, and filterStackTrace then removes internal frames so the resolver log only sees the filtered trace"() {
given: "Captured System.err"
def originalErr = System.err
def baos = new ByteArrayOutputStream()
System.setErr(new PrintStream(baos, true))
given: "captures of both the resolver logger and the StackTrace logger"
def resolverLog = new LogCapture(GrailsExceptionResolver)
def stackLog = new LogCapture(DefaultStackTraceFilterer.STACK_LOG_NAME)

and: "A resolver whose config opts in to full stack trace logging"
def config = Mock(Config)
Expand Down Expand Up @@ -297,22 +291,30 @@ class GrailsExceptionResolverSpec extends Specification {
resolver.filterStackTrace(exception)
resolver.logStackTrace(exception, request)

then: "Both loggers emit"
System.err.flush()
def captured = baos.toString()
captured.contains('ERROR StackTrace ')
captured.contains('Full Stack Trace:')
captured.contains('o.g.web.errors.GrailsExceptionResolver') ||
captured.contains('org.grails.web.errors.GrailsExceptionResolver')
then: "Both loggers emit exactly once"
stackLog.events.size() == 1
resolverLog.events.size() == 1
stackLog.events[0].formattedMessage.contains(StackTraceFilterer.FULL_STACK_TRACE_MESSAGE)
resolverLog.events[0].loggerName == GrailsExceptionResolver.name

and: "The application frame appears in both log entries"
captured.count('com.example.MyController.show(MyController.groovy:10)') == 2
and: "The application frame appears in both the unfiltered and filtered log entries"
[stackLog.events[0], resolverLog.events[0]].every { event ->
event.throwableProxy.stackTraceElementProxyArray.any {
it.stackTraceElement.className == 'com.example.MyController'
}
}

and: "The internal frame appears only once — in the unfiltered StackTrace entry, not in the filtered resolver entry"
captured.count('java.lang.reflect.Method.invoke(Method.java:580)') == 1
and: "The internal frame appears only in the unfiltered StackTrace entry, not in the filtered resolver entry"
stackLog.events[0].throwableProxy.stackTraceElementProxyArray.any {
it.stackTraceElement.className == 'java.lang.reflect.Method'
}
resolverLog.events[0].throwableProxy.stackTraceElementProxyArray.every {
it.stackTraceElement.className != 'java.lang.reflect.Method'
}

cleanup:
System.setErr(originalErr)
resolverLog.close()
stackLog.close()
}

void "getRequestLogMessage masks excluded request parameters case-insensitively"() {
Expand Down
Loading