001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest.logger; 014 015import static org.apache.juneau.rest.logger.CallLoggingDetail.*; 016import static org.apache.juneau.Enablement.*; 017import static org.apache.juneau.common.internal.StringUtils.*; 018import static java.util.logging.Level.*; 019 020import jakarta.servlet.http.*; 021 022import org.apache.juneau.cp.*; 023import org.apache.juneau.rest.*; 024 025/** 026 * Default implementation of a {@link CallLogger} that only logs REST call errors unless no-log is enabled on the request. 027 * 028 * <p> 029 * Useful for REST tests where you know that a particular call is going to produce an error response and you don't want that 030 * response to be logged producing noisy test output. 031 * 032 * <p> 033 * Requests can be tagged as no-log (meaning don't log if there's an error) in any of the following ways: 034 * <ul> 035 * <li>A <js>"No-Trace: true"</js> header. 036 * <li>A <js>"noTrace=true"</js> query parameter. 037 * <li>A <js>"NoTrace"</js> request attribute with a string value of <js>"true"</js>. 038 * </ul> 039 * 040 * <h5 class='section'>Configured Settings:</h5> 041 * <ul> 042 * <li>Logs to the {@link RestContext#getLogger() context logger}. 043 * <li>Only calls with status code >=400 will be logged. 044 * <li>Logs full request and response entity. 045 * </ul> 046 * 047 * <h5 class='section'>See Also:</h5><ul> 048 * <li class='link'><a class="doclink" href="../../../../../index.html#jrs.LoggingAndDebugging">Logging / Debugging</a> 049 * </ul> 050 */ 051public class BasicTestCallLogger extends CallLogger { 052 053 /** 054 * Constructor. 055 * 056 * @param beanStore The bean store containing injectable beans for this logger. 057 */ 058 public BasicTestCallLogger(BeanStore beanStore) { 059 super(beanStore); 060 } 061 062 @Override 063 protected Builder init(BeanStore beanStore) { 064 return super.init(beanStore) 065 .normalRules( // Rules when debugging is not enabled. 066 CallLoggerRule.create(beanStore) // Log 500+ errors with status-line and header information. 067 .statusFilter(x -> x >= 400) 068 .level(SEVERE) 069 .requestDetail(HEADER) 070 .responseDetail(HEADER) 071 .enabled(CONDITIONAL) 072 .enabledPredicate(x -> ! isNoTrace(x)) // Only log if it's not a no-trace request. 073 .logStackTrace() 074 .build(), 075 CallLoggerRule.create(beanStore) // Log 400-500 errors with just status-line information. 076 .statusFilter(x -> x >= 400) 077 .level(WARNING) 078 .requestDetail(STATUS_LINE) 079 .responseDetail(STATUS_LINE) 080 .enabled(CONDITIONAL) 081 .enabledPredicate(x -> ! isNoTrace(x)) // Only log if it's not a no-trace request. 082 .logStackTrace() 083 .build() 084 ) 085 .debugRules( // Rules when debugging is enabled. 086 CallLoggerRule.create(beanStore) // Log everything with full details. 087 .level(SEVERE) 088 .requestDetail(ENTITY) 089 .responseDetail(ENTITY) 090 .logStackTrace() 091 .build() 092 ) 093 ; 094 } 095 096 private static boolean isNoTrace(HttpServletRequest req) { 097 Object o = req.getAttribute("NoTrace"); 098 if (o != null) 099 return "true".equalsIgnoreCase(o.toString()); 100 String s = req.getHeader("No-Trace"); 101 if (s != null) 102 return "true".equalsIgnoreCase(s); 103 return emptyIfNull(req.getQueryString()).contains("noTrace=true"); 104 } 105}