স্প্রিং বুট - একক জায়গায় ব্যতিক্রম সহ সমস্ত অনুরোধ এবং প্রতিক্রিয়াগুলি কীভাবে লগ করবেন?


215

আমি স্প্রিং বুট নিয়ে রেস্ট এপি নিয়ে কাজ করছি। আমার সমস্ত অনুরোধগুলি ইনপুট প্যারামের সাথে (পদ্ধতিগুলির সাথে, যেমন GET, পোষ্ট, ইত্যাদি) লগ ইন করতে হবে, অনুরোধের পথ, ক্যোয়ারী স্ট্রিং, এই অনুরোধের সাথে সম্পর্কিত শ্রেণির পদ্ধতি, এই ক্রিয়াটির সাড়া এবং সাফল্য উভয়ই।

উদাহরণস্বরূপ:

সফল অনুরোধ:

http://example.com/api/users/1

লগকে এই জাতীয় কিছু দেখা উচিত:

{
   HttpStatus: 200,
   path: "api/users/1",
   method: "GET",
   clientIp: "0.0.0.0",
   accessToken: "XHGu6as5dajshdgau6i6asdjhgjhg",
   method: "UsersController.getUser",
   arguments: {
     id: 1 
   },
   response: {
      user: {
        id: 1,
        username: "user123",
        email: "user123@example.com"   
      }
   },
   exceptions: []       
}

বা ত্রুটি সহ অনুরোধ:

http://example.com/api/users/9999

লগ এই জাতীয় কিছু হওয়া উচিত:

    {
       HttpStatus: 404,
       errorCode: 101,                 
       path: "api/users/9999",
       method: "GET",
       clientIp: "0.0.0.0",
       accessToken: "XHGu6as5dajshdgau6i6asdjhgjhg",
       method: "UsersController.getUser",
       arguments: {
         id: 9999 
       },
       returns: {            
       },
       exceptions: [
         {
           exception: "UserNotFoundException",
           message: "User with id 9999 not found",
           exceptionId: "adhaskldjaso98d7324kjh989",
           stacktrace: ...................    
       ]       
    }

সফল এবং ত্রুটি উভয় ক্ষেত্রেই এই সত্তা সম্পর্কিত কাস্টম তথ্য সহ আমি অনুরোধ / প্রতিক্রিয়াটিকে একটি একক সত্তা হিসাবে দেখতে চাই।

এটি অর্জনের জন্য বসন্তের সেরা অনুশীলনটি কী, ফিল্টারগুলির সাথে থাকতে পারে? যদি হ্যাঁ, আপনি কি দৃ concrete় উদাহরণ দিতে পারেন?

(আমি @ControllerAdvice এবং @ ExceptionHandler এর সাথে খেলেছি, তবে আমি যেমন উল্লেখ করেছি, আমার একক স্থানে সমস্ত সাফল্য এবং ত্রুটি অনুরোধগুলি পরিচালনা করতে হবে (এবং একক লগ))।


সম্ভবত একটি লগিং ServletFilter (যেমন মাধ্যমে stackoverflow.com/a/2171633/995891 ), অন্যথায় HandlerInterceptorকিন্তু যে পাশাপাশি উত্তর উল্লেখিত প্রতিক্রিয়া লগ-ইন সঙ্গে কাজ নাও করতে পারে: concretepage.com/spring/spring-mvc/... - HandlerInterceptor অ্যাক্সেস আছে পদ্ধতিতে (পদ্ধতি: "ইউজারসেন্ট্রোলআর। ব্যবহারকারী") যদিও। এটি কোনও সার্লেট ফিল্টারটিতে পরিচিত নয়।
জ্যাপল

1
তবুও, আপনি যদি কোনও ফিল্টার যোগ করেন বা অ্যাপ্লিকেশন স্তরটিতে যা কিছু সমাধান করেন, আপনি সমস্ত অনুরোধটি লগ করতে পারবেন না, তবে HTTP 500 সার্ভার ত্রুটি লগ হবে না, এমন সময় যে কারণে একটি অপ্রয়োজনীয় ব্যতিক্রম অ্যাপ্লিকেশন স্তরে ছুঁড়ে ফেলা হবে, ত্রুটি পৃষ্ঠায় ডিফল্ট এম্বেড থাকা টমক্যাটগুলি ব্যতিক্রম গিলে ফেলার পরে প্রদর্শিত হবে এবং অবশ্যই লগটি সংরক্ষণ করবে না। এছাড়াও আপনি যদি ব্যবহারকারী 1717243 উত্তরটি পরীক্ষা করেন তবে কোনও ব্যতিক্রমের ক্ষেত্রে তিনি আবার অনুরোধটি লগইন করবেন না তবে তিনি ব্যতিক্রমটি লগ করবেন (!!)।
আন্তজভাবাদেভ

সেই লগ বিন্যাসটি আপনার লেখা প্রতিটি চরিত্রের সাথে সঙ্গতিপূর্ণ হতে পারে? মনে হয় জেএসওন অনুবাদটি আপনার ক্ষেত্রে সর্বোত্তম হতে পারে: LogClass{ getRequestAndSaveIt()} Gson.toJson(LogClass)সিউডোকোড হিসাবে
ভেল

1
ভবিষ্যতের পাঠকরা আমার উত্তর (এই মন্তব্যে অনুসরণ করার url) থেকে উপকৃত হতে পারেন। মূলত, আমি এই প্রশ্নটি সম্পর্কে বিভিন্ন পোস্ট একসাথে ফ্র্যাঙ্কেন স্টেইন করতে সক্ষম হয়েছি। দয়া করে হাত দিয়ে চেষ্টা করার আগে অ্যাকিউউটর উত্তরটি (নীচে উত্তরগুলিতে) বিবেচনা করুন। তবে আমি যে উত্তরটি পোস্ট করছি তা "400, 404, 500" (যে কোনও / সমস্ত) লগ করার অনুমতি দেয় তবে অর্ডার-অগ্রাধিকারটি সর্বনিম্ন-অগ্রাধিকারের সাথে সেট করে (বা কোডটি দেখলে "8" এর মধ্যে)। stackoverflow.com/questions/10210645/...
granadaCoder

আমি এখান থেকে লগিংয়ের জন্য বসন্তের ডক্সগুলি অনুসরণ করেছি: ডকস.স্প্রিং.আইও
স্প্রিং-

উত্তর:


147

কোনও ইন্টারসেপ্টর, ফিল্টার, উপাদান, দিক, ইত্যাদি লিখবেন না, এটি একটি খুব সাধারণ সমস্যা এবং এটি বহুবার সমাধান করা হয়েছে।

স্প্রিং বুটের অ্যাকুয়েটর নামে একটি মডিউল রয়েছে যা বাক্সের বাইরে এইচটিটিপি অনুরোধ সরবরাহ করে provides /trace(SB1.x) বা /actuator/httptrace(SB2.0 +) এ ম্যাপযুক্ত একটি এন্ডপয়েন্ট রয়েছে যা আপনাকে সর্বশেষ 100 টি HTTP অনুরোধগুলি প্রদর্শন করবে। প্রতিটি অনুরোধ লগ করতে আপনি এটি কাস্টমাইজ করতে পারেন, বা একটি ডিবিতে লিখতে পারেন।

আপনি যে শেষ পয়েন্টগুলি চান তা পেতে, আপনার বসন্ত-বুট-স্টার্টার-অ্যাকুয়েটর নির্ভরতা এবং আপনি যে শেষ পয়েন্টগুলি সন্ধান করছেন এটি "শ্বেতলিস্ট" তৈরি করতে এবং সম্ভবত এটির জন্য সুরক্ষা সেটআপ বা অক্ষম করতে হবে।

এছাড়াও, এই অ্যাপ্লিকেশনটি কোথায় চলবে? আপনি কি PaaS ব্যবহার করবেন? হোস্টিং প্রদানকারী, Heroku উদাহরণস্বরূপ, অনুরোধ লগিং তাদের সেবা অংশ হিসেবে এবং আপনাকে যা করতে প্রয়োজন হবে না কোন সবটা তারপর কোডিং।


4
আর কোন বিবরণ? আমি github.com/spring-projects/spring-boot/tree/master/… পেয়েছি , কিন্তু এর চেয়ে বেশি কিছু নেই।
টম হাওয়ার্ড

16
এটি ডিবাগিংয়ের জন্য ব্যবহার করা যাবে না: অযৌক্তিক অনুরোধগুলি (উদাহরণস্বরূপ বসন্ত সুরক্ষা সহ) লগ হয় না।
বেকস

11
প্রকৃতপক্ষে অ্যাকিউটরেটের HTTP লগিংয়ের জন্য কোনও নির্দিষ্ট উপাদান নেই। / ট্রেস - শুধুমাত্র শেষ এন অনুরোধগুলি দেখান।
ভ্লাদিমির ফিলিপচেনকো

18
@ লাইক_লভ, কীভাবে অ্যাকিউইউটারকে এমনভাবে সংকুচিত করবেন যে এটি ফাইল করার জন্য লগিংয়ের অনুরোধটি (এছাড়াও পোষ্ট বডি)?

11
ট্রেস আপনার জন্য অনুরোধ এবং প্রতিক্রিয়া বডি লগ করবে না .... অন্য সমস্ত কিছু (শিরোনাম ইত্যাদি) তবে সেগুলি।
লেককি

94

বসন্ত ইতিমধ্যে একটি ফিল্টার সরবরাহ করে যা এই কাজ করে। আপনার কনফিগারেশনে নিম্নলিখিত শিম যুক্ত করুন

@Bean
public CommonsRequestLoggingFilter requestLoggingFilter() {
    CommonsRequestLoggingFilter loggingFilter = new CommonsRequestLoggingFilter();
    loggingFilter.setIncludeClientInfo(true);
    loggingFilter.setIncludeQueryString(true);
    loggingFilter.setIncludePayload(true);
    loggingFilter.setMaxPayloadLength(64000);
    return loggingFilter;
}

লগ স্তর পরিবর্তন করতে ভুলবেন না org.springframework.web.filter.CommonsRequestLoggingFilterকরতে DEBUG


75
মনে রাখবেন এটি প্রতিক্রিয়াগুলি লগ করে না , কেবলমাত্র অনুরোধগুলি।
উইম দেবলাউয়

1
কেবল অনুরোধ আছে। CommonsRequestLoggingFilter ব্যবহার করে প্রতিক্রিয়াগুলিতে লগ কিভাবে করবেন?
ব্যবহারকারী2602807

3
এছাড়াও এটি ব্যাতিক্রম লগ করে না
ভেন্ডিগওয়ার

ঠিক আছে, এটি একটি অনুরোধ লগিং ফিল্টার হিসাবে প্রত্যাশিত। আরও এখানে এখানে: ডকসস.স্প্রিং.আইও
যোগেশ

4
আপনার কাছে যদি বড় জেএসএন বডি থাকে তবে পুরো অনুরোধের বডিটিতে লগ করার জন্য পেডলোডের দৈর্ঘ্যকে একটি বড় সংখ্যায় সেট করুন। loggingFilter.setMaxPayloadLength (100000);
ভেঙ্কটেশ নান্নান

57

javax.servlet.Filterজাভা পদ্ধতিতে চালিত হওয়া লগ করার প্রয়োজন না থাকলে আপনি ব্যবহার করতে পারেন ।

কিন্তু এই প্রয়োজনীয়তা সঙ্গে আপনি সঞ্চিত এক্সেস তথ্য আছে handlerMappingএর DispatcherServlet। এটি বলেছিল, আপনি DispatcherServletঅনুরোধ / প্রতিক্রিয়া জুটির লগিং সম্পন্ন করতে ওভাররাইড করতে পারেন।

নীচে এমন একটি ধারণার উদাহরণ দেওয়া হয়েছে যা আপনার প্রয়োজন অনুসারে আরও বাড়ানো ও গ্রহণ করা যেতে পারে।

public class LoggableDispatcherServlet extends DispatcherServlet {

    private final Log logger = LogFactory.getLog(getClass());

    @Override
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (!(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper(request);
        }
        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper(response);
        }
        HandlerExecutionChain handler = getHandler(request);

        try {
            super.doDispatch(request, response);
        } finally {
            log(request, response, handler);
            updateResponse(response);
        }
    }

    private void log(HttpServletRequest requestToCache, HttpServletResponse responseToCache, HandlerExecutionChain handler) {
        LogMessage log = new LogMessage();
        log.setHttpStatus(responseToCache.getStatus());
        log.setHttpMethod(requestToCache.getMethod());
        log.setPath(requestToCache.getRequestURI());
        log.setClientIp(requestToCache.getRemoteAddr());
        log.setJavaMethod(handler.toString());
        log.setResponse(getResponsePayload(responseToCache));
        logger.info(log);
    }

    private String getResponsePayload(HttpServletResponse response) {
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {

            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                int length = Math.min(buf.length, 5120);
                try {
                    return new String(buf, 0, length, wrapper.getCharacterEncoding());
                }
                catch (UnsupportedEncodingException ex) {
                    // NOOP
                }
            }
        }
        return "[unknown]";
    }

    private void updateResponse(HttpServletResponse response) throws IOException {
        ContentCachingResponseWrapper responseWrapper =
            WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        responseWrapper.copyBodyToResponse();
    }

}

HandlerExecutionChain - অনুরোধ হ্যান্ডলার সম্পর্কে তথ্য রয়েছে।

তারপরে আপনি এই প্রেরককে নিম্নলিখিত হিসাবে নিবন্ধভুক্ত করতে পারেন:

    @Bean
    public ServletRegistrationBean dispatcherRegistration() {
        return new ServletRegistrationBean(dispatcherServlet());
    }

    @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServlet dispatcherServlet() {
        return new LoggableDispatcherServlet();
    }

এবং লগগুলির নমুনা এখানে:

http http://localhost:8090/settings/test
i.g.m.s.s.LoggableDispatcherServlet      : LogMessage{httpStatus=500, path='/error', httpMethod='GET', clientIp='127.0.0.1', javaMethod='HandlerExecutionChain with handler [public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)] and 3 interceptors', arguments=null, response='{"timestamp":1472475814077,"status":500,"error":"Internal Server Error","exception":"java.lang.RuntimeException","message":"org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.RuntimeException","path":"/settings/test"}'}

http http://localhost:8090/settings/params
i.g.m.s.s.LoggableDispatcherServlet      : LogMessage{httpStatus=200, path='/settings/httpParams', httpMethod='GET', clientIp='127.0.0.1', javaMethod='HandlerExecutionChain with handler [public x.y.z.DTO x.y.z.Controller.params()] and 3 interceptors', arguments=null, response='{}'}

http http://localhost:8090/123
i.g.m.s.s.LoggableDispatcherServlet      : LogMessage{httpStatus=404, path='/error', httpMethod='GET', clientIp='127.0.0.1', javaMethod='HandlerExecutionChain with handler [public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)] and 3 interceptors', arguments=null, response='{"timestamp":1472475840592,"status":404,"error":"Not Found","message":"Not Found","path":"/123"}'}

হালনাগাদ

ত্রুটির ক্ষেত্রে স্প্রিং স্বয়ংক্রিয় ত্রুটি পরিচালনা করে। অতএব, BasicErrorController#errorঅনুরোধ হ্যান্ডলার হিসাবে প্রদর্শিত হয়। আপনি যদি আসল অনুরোধ হ্যান্ডলারটি সংরক্ষণ করতে চান, তবে আপনি মূল আচরণটিকে ক্যাশে করতে প্রথমে বলা spring-webmvc-4.2.5.RELEASE-sources.jar!/org/springframework/web/servlet/DispatcherServlet.java:971হয়ে #processDispatchResultথাকে এই আচরণটি ওভাররাইড করতে পারেন ।


2
যখন প্রতিক্রিয়া একটি স্ট্রিম হয় এবং স্রোত সন্ধানকে সমর্থন করে না তখন কী ঘটে? উপরেরগুলি কি এখনও কাজ করবে?
টম হাওয়ার্ড

আমি যে পদ্ধতিটি আহ্বান করা হয়েছিল তার বিষয়ে যত্ন নিচ্ছি না, কেবলমাত্র প্রাপ্ত ডেটা প্রাপ্ত এবং প্রেরণ করা। ফিল্টারটি আমাকে সঠিক দিকে নির্দেশ করছে এবং @ ike_love এর প্রতিক্রিয়া আমাকে github.com/spring-projects/spring-boot/blob/master/…
টম হাওয়ার্ড

@ টমহওয়ার্ড এএফাইক, বসন্তে "প্রতিক্রিয়া লগিং" বক্সের বাইরে নেই। অতএব আপনি প্রতিক্রিয়া লগিং যুক্তি যুক্ত করে WebRequestTraceFilter বা AbstractRequestLoggingFilter প্রসারিত করতে পারেন।
এইচএন

ঠিক কাজ করে!
পাভেল ভ্লাসভ

@ আপনি কেন এর জন্য ডিসপ্যাচার সার্লেট ব্যবহার করেছেন? doFilter এ ফিল্টার সহ একই লগইন যুক্ত করা যাবে না?
ভেন্দিগওয়ার

39

Logbook গ্রন্থাগার বিশেষভাবে লগিং HTTP অনুরোধ এবং প্রতিক্রিয়া জন্য তৈরি করা হয়। এটি একটি বিশেষ স্টার্টার লাইব্রেরি ব্যবহার করে স্প্রিং বুট সমর্থন করে।

স্প্রিং বুটে লগিং সক্ষম করতে আপনাকে যা করতে হবে তা হল আপনার প্রকল্পের নির্ভরতাগুলিতে লাইব্রেরি যুক্ত করা। উদাহরণস্বরূপ ধরে নেওয়া যে আপনি মাভেন ব্যবহার করছেন:

<dependency>
    <groupId>org.zalando</groupId>
    <artifactId>logbook-spring-boot-starter</artifactId>
    <version>1.5.0</version>
</dependency>

ডিফল্টরূপে লগিং আউটপুটটি দেখতে এরকম দেখাচ্ছে:

{
  "origin" : "local",
  "correlation" : "52e19498-890c-4f75-a06c-06ddcf20836e",
  "status" : 200,
  "headers" : {
    "X-Application-Context" : [
      "application:8088"
    ],
    "Content-Type" : [
      "application/json;charset=UTF-8"
    ],
    "Transfer-Encoding" : [
      "chunked"
    ],
    "Date" : [
      "Sun, 24 Dec 2017 13:10:45 GMT"
    ]
  },
  "body" : {
    "thekey" : "some_example"
  },
  "duration" : 105,
  "protocol" : "HTTP/1.1",
  "type" : "response"
}

এটি অনুরোধটি পরিচালনা করছে এমন শ্রেণীর নাম আউটপুট দেয় না। লাইব্রেরিতে কাস্টম লগার লেখার জন্য কিছু ইন্টারফেস রয়েছে।


4
একটি ন্যূনতম বসন্ত বুট অ্যাপের উপর নির্ভরতা হিসাবে যুক্ত হয়েছে এবং চালানোর চেষ্টা করেছে - আমার অ্যাপ্লিকেশনটিতে কোনও পরিবর্তন নেই, লগিং আউটপুট মোটেও নয়। আমি মনে করি এই অতিরিক্ত কিছু নির্ভরতা বা ক্লাস আছে? ফিল্টার হিসাবে এটি নিবন্ধভুক্ত করার পরেও কিছু করার মনে হয় না।
eis

1
@ আইস আপনাকে এখানে ডক্সে বর্ণিত ফিল্টার হিসাবে নিবন্ধিত করতে হবে। github.com/zalando/logbook
প্রতীক

1
লগবুক ডক বলেছেন: "লগবুকটি স্প্রিং বুট ব্যবহারকারীদের জন্য একটি সুবিধাজনক অটো কনফিগারেশন নিয়ে আসে It এটি নীচের সমস্ত অংশ বুদ্ধিমান ডিফল্ট সহ স্বয়ংক্রিয়ভাবে সেট আপ করে।" কিন্তু এটা কাজ করে না।
লিওস লিটারাক

5
@ লিজলাইটারাক আমি বিশ্বাস করি logging.level.org.zalando.logbook=TRACE যে আপনার application.properties( যোগ করা হয়েছে হিসাবে Readme) আপনার যোগ করতে হবে
টলকিয়েনওয়াএসপি

2
লগবুকের স্বয়ংস্কৃতিটি বসন্ত-বুট v2.0.5-এ কাজ করছে বলে মনে হচ্ছে না
যশবীর রানা

26

আমি application.propertiesলগ ফাইলের মধ্যে অনুরোধ / প্রতিক্রিয়াগুলি, মেথড ইউআরএল প্রিন্ট করতে লগিং স্তরটিকে সংজ্ঞায়িত করেছি

logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate.SQL=INFO
logging.file=D:/log/myapp.log

আমি স্প্রিং বুট ব্যবহার করেছি।


2
হ্যাঁ, আপনি ঠিক বলেছেন - অনুরূপ অন্যান্য লগ ফাইলে একই লগ ফাইলটিতে অনুরোধ পাওয়ার জন্য এটি বৈধ উত্তর। তবে, @ মোমোরো জিইটি, পোস্ট ইত্যাদি লগ করতে এবং পৃথক ফাইলে (যেমন আমি বুঝতে পেরেছি) জিজ্ঞাসা করতে চেয়েছিলাম
মানুশিন ইগর

4
আমার এটা ভাল লেগেছে. শূন্য নাটক
কুইরিনো গ্রাভাসিও

1
আপনি যদি শিরোনামগুলিকে লগে অন্তর্ভুক্ত করতে চান তবে আপনার যুক্ত করা উচিত: "স্প্রিং। Htp.log-অনুরোধ-বিবরণ = সত্য" আপনার কাছে অ্যাপ্লিকেশন.প্রপার্টি ফাইল।
jfajunior

20

এখানে কিভাবে আমি ব্যবহার দ্বারা বসন্ত ডেটা বাকি এটা করতে হয় org.springframework.web.util.ContentCachingRequestWrapper এবং org.springframework.web.util.ContentCachingResponseWrapper

/**
 * Doogies very cool HTTP request logging
 *
 * There is also {@link org.springframework.web.filter.CommonsRequestLoggingFilter}  but it cannot log request method
 * And it cannot easily be extended.
 *
 * https://mdeinum.wordpress.com/2015/07/01/spring-framework-hidden-gems/
 * http://stackoverflow.com/questions/8933054/how-to-read-and-copy-the-http-servlet-response-output-stream-content-for-logging
 */
public class DoogiesRequestLogger extends OncePerRequestFilter {

  private boolean includeResponsePayload = true;
  private int maxPayloadLength = 1000;

  private String getContentAsString(byte[] buf, int maxLength, String charsetName) {
    if (buf == null || buf.length == 0) return "";
    int length = Math.min(buf.length, this.maxPayloadLength);
    try {
      return new String(buf, 0, length, charsetName);
    } catch (UnsupportedEncodingException ex) {
      return "Unsupported Encoding";
    }
  }

  /**
   * Log each request and respponse with full Request URI, content payload and duration of the request in ms.
   * @param request the request
   * @param response the response
   * @param filterChain chain of filters
   * @throws ServletException
   * @throws IOException
   */
  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

    long startTime = System.currentTimeMillis();
    StringBuffer reqInfo = new StringBuffer()
     .append("[")
     .append(startTime % 10000)  // request ID
     .append("] ")
     .append(request.getMethod())
     .append(" ")
     .append(request.getRequestURL());

    String queryString = request.getQueryString();
    if (queryString != null) {
      reqInfo.append("?").append(queryString);
    }

    if (request.getAuthType() != null) {
      reqInfo.append(", authType=")
        .append(request.getAuthType());
    }
    if (request.getUserPrincipal() != null) {
      reqInfo.append(", principalName=")
        .append(request.getUserPrincipal().getName());
    }

    this.logger.debug("=> " + reqInfo);

    // ========= Log request and response payload ("body") ========
    // We CANNOT simply read the request payload here, because then the InputStream would be consumed and cannot be read again by the actual processing/server.
    //    String reqBody = DoogiesUtil._stream2String(request.getInputStream());   // THIS WOULD NOT WORK!
    // So we need to apply some stronger magic here :-)
    ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
    ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);

    filterChain.doFilter(wrappedRequest, wrappedResponse);     // ======== This performs the actual request!
    long duration = System.currentTimeMillis() - startTime;

    // I can only log the request's body AFTER the request has been made and ContentCachingRequestWrapper did its work.
    String requestBody = this.getContentAsString(wrappedRequest.getContentAsByteArray(), this.maxPayloadLength, request.getCharacterEncoding());
    if (requestBody.length() > 0) {
      this.logger.debug("   Request body:\n" +requestBody);
    }

    this.logger.debug("<= " + reqInfo + ": returned status=" + response.getStatus() + " in "+duration + "ms");
    if (includeResponsePayload) {
      byte[] buf = wrappedResponse.getContentAsByteArray();
      this.logger.debug("   Response body:\n"+getContentAsString(buf, this.maxPayloadLength, response.getCharacterEncoding()));
    }

    wrappedResponse.copyBodyToResponse();  // IMPORTANT: copy content of response back into original response

  }


}

18

যদি আপনি স্প্রিং এওপি চেষ্টা করে দেখতে না পান তবে এটি এমন কিছু যা আমি লগিংয়ের উদ্দেশ্যে অনুসন্ধান করে চলেছি এবং এটি আমার পক্ষে বেশ ভালভাবে কাজ করে। এটি লগ অনুরোধগুলির অভ্যাস করবে না যা সংজ্ঞায়িত করা হয়নি এবং যদিও অনুরোধের প্রচেষ্টা ব্যর্থ হয়েছে।

এই তিনটি নির্ভরতা যুক্ত করুন

spring-aop, aspectjrt, aspectjweaver

এটি আপনার এক্সএমএল কনফিগারেশন ফাইলে যুক্ত করুন <aop:aspectj-autoproxy/>

একটি টীকা তৈরি করুন যা পয়েন্টকুট হিসাবে ব্যবহৃত হতে পারে

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface EnableLogging {
ActionType actionType();
}

আপনি লগ করতে চান এমন আপনার সমস্ত বাকি এপিআই পদ্ধতিতে টীকা দিন

@EnableLogging(actionType = ActionType.SOME_EMPLOYEE_ACTION)
@Override
public Response getEmployees(RequestDto req, final String param) {
...
}

এখন দিক থেকে। এই শ্রেণীর মধ্যে থাকা প্যাকেজটিকে উপাদান-স্ক্যান করুন।

@Aspect
@Component
public class Aspects {

@AfterReturning(pointcut = "execution(@co.xyz.aspect.EnableLogging * *(..)) && @annotation(enableLogging) && args(reqArg, reqArg1,..)", returning = "result")
public void auditInfo(JoinPoint joinPoint, Object result, EnableLogging enableLogging, Object reqArg, String reqArg1) {

    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
            .getRequest();

    if (result instanceof Response) {
        Response responseObj = (Response) result;

    String requestUrl = request.getScheme() + "://" + request.getServerName()
                + ":" + request.getServerPort() + request.getContextPath() + request.getRequestURI()
                + "?" + request.getQueryString();

String clientIp = request.getRemoteAddr();
String clientRequest = reqArg.toString();
int httpResponseStatus = responseObj.getStatus();
responseObj.getEntity();
// Can log whatever stuff from here in a single spot.
}


@AfterThrowing(pointcut = "execution(@co.xyz.aspect.EnableLogging * *(..)) && @annotation(enableLogging) && args(reqArg, reqArg1,..)", throwing="exception")
public void auditExceptionInfo(JoinPoint joinPoint, Throwable exception, EnableLogging enableLogging, Object reqArg, String reqArg1) {

    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
            .getRequest();

    String requestUrl = request.getScheme() + "://" + request.getServerName()
    + ":" + request.getServerPort() + request.getContextPath() + request.getRequestURI()
    + "?" + request.getQueryString();

    exception.getMessage();
    exception.getCause();
    exception.printStackTrace();
    exception.getLocalizedMessage();
    // Can log whatever exceptions, requests, etc from here in a single spot.
    }
}

যখন ম্যাচিং পদ্ধতি কার্যকরভাবে সাধারণত ফিরে আসে তখন অ্যাফটারেরটার্নিং পরামর্শটি চলে।

কোনও ম্যাচিং পদ্ধতি কার্যকর হলে একটি ব্যতিক্রম ছুঁড়ে ফেলে দিয়ে চলে যাওয়ার পরে @ আফটারথ্রিংয়ের পরামর্শ চলে।

বিস্তারিত জানতে চাইলে এর মাধ্যমে পড়ুন। http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html


1
এটি পদ্ধতিটির আমন্ত্রণটি লগ করে, এইচটিটিপি স্তরে আসলে কী প্রাপ্ত হয়েছিল এবং প্রেরণ করা হয়েছিল তা নয়।
টম হাওয়ার্ড

1
দেহের অনুরোধ কীভাবে লিখবেন? আমার ক্ষেত্রে এটি পোষ্ট বডি। অনুরোধ.জেটআরেডার বা getInputStream এ ত্রুটি পাই যে স্ট্রিমটি বন্ধ রয়েছে।

13

যোগ করার পরে actuators বসন্ত বুট bassed আবেদন আপনি /traceসর্বশেষ অনুরোধ informations সঙ্গে শেষবিন্দু পাওয়া যায়। এই শেষ পয়েন্টটি ট্রেসরিপোসিটরির উপর ভিত্তি করে কাজ করছে এবং ডিফল্ট রূপায়ণ হ'ল InMemoryTraceRepository যা সর্বশেষ 100 টি কল সংরক্ষণ করে। আপনি নিজের দ্বারা এই ইন্টারফেসটি প্রয়োগ করে এটি পরিবর্তন করতে পারেন এবং এটি একটি স্প্রিং বিন হিসাবে উপলব্ধ করতে পারেন। উদাহরণস্বরূপ লগ করার জন্য সমস্ত অনুরোধ লগ করার জন্য (এবং এখনও /traceশেষ পয়েন্টে তথ্য সরবরাহের জন্য ডিফল্ট বাস্তবায়নটি প্রাথমিক স্টোরেজ হিসাবে ব্যবহার করে) আমি এই জাতীয় প্রয়োগটি ব্যবহার করছি:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
import org.springframework.boot.actuate.trace.Trace;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;


@Component
public class LoggingTraceRepository implements TraceRepository {

  private static final Logger LOG = LoggerFactory.getLogger(LoggingTraceRepository.class);
  private final TraceRepository delegate = new InMemoryTraceRepository();

  @Override
  public List<Trace> findAll() {
    return delegate.findAll();
  }

  @Override
  public void add(Map<String, Object> traceInfo) {
    LOG.info(traceInfo.toString());
    this.delegate.add(traceInfo);
  }
}

এই traceInfoমানচিত্র অনুরোধ এবং ফর্ম এই ধরনের প্রতিক্রিয়া সম্পর্কে মৌলিক তথ্য রয়েছে: {method=GET, path=/api/hello/John, headers={request={host=localhost:8080, user-agent=curl/7.51.0, accept=*/*}, response={X-Application-Context=application, Content-Type=text/plain;charset=UTF-8, Content-Length=10, Date=Wed, 29 Mar 2017 20:41:21 GMT, status=200}}}। এখানে কোনও প্রতিক্রিয়া সামগ্রী নেই।

সম্পাদনা করুন! পোস্ট ডেটা লগ করা হচ্ছে

আপনি ওয়েবআরকুয়েস্টট্রেসফিল্টারকে ওভাররাইড করে পোষ্টের ডেটা অ্যাক্সেস করতে পারেন তবে এটিকে একটি ভাল ধারণা বলে মনে করবেন না (যেমন সমস্ত আপলোড করা ফাইলের সামগ্রী লগতে যাবে) এখানে নমুনা কোড রয়েছে, তবে এটি ব্যবহার করবেন না :

package info.fingo.nuntius.acuate.trace;

import org.apache.commons.io.IOUtils;
import org.springframework.boot.actuate.trace.TraceProperties;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.actuate.trace.WebRequestTraceFilter;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.Map;

@Component
public class CustomWebTraceFilter extends WebRequestTraceFilter {

  public CustomWebTraceFilter(TraceRepository repository, TraceProperties properties) {
    super(repository, properties);
}

  @Override
  protected Map<String, Object> getTrace(HttpServletRequest request) {
    Map<String, Object> trace = super.getTrace(request);
    String multipartHeader = request.getHeader("content-type");
    if (multipartHeader != null && multipartHeader.startsWith("multipart/form-data")) {
        Map<String, Object> parts = new LinkedHashMap<>();
        try {
            request.getParts().forEach(
                    part -> {
                        try {
                            parts.put(part.getName(), IOUtils.toString(part.getInputStream(), Charset.forName("UTF-8")));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
            );
        } catch (IOException | ServletException e) {
            e.printStackTrace();
        }
        if (!parts.isEmpty()) {
            trace.put("multipart-content-map", parts);
        }
    }
    return trace;
  }
}

1
পোষ্ট বডি সম্পর্কে কি?
পাভেল ভাইজানকিন

@ ডার্ট আমি আপনার জন্য উদাহরণ যুক্ত করেছি
পিয়োটার চৌওয়ানিক

1
আমি এই জাতীয় কিছু করছিলাম, তবে সমস্যাটি হচ্ছে প্রতিক্রিয়া বডিটি উপলব্ধ নয় TraceRepository, আমরা কীভাবে এটিতে অ্যাক্সেস করতে পারি?
আমির পাশাজাদেহে

@ আমিরপাশাজাদেহ আপনাকে ওভাররাইড করতে হবে protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)তবে আমি নিশ্চিত নই যে এই ফিল্টারটি কখন কার্যকর হবে - অনুরোধের পর্যায়ে থাকতে পারে, সুতরাং প্রতিক্রিয়া সংস্থাটি প্রস্তুত থাকবে না।
পিয়োটার চৌওয়ানিক

1
@ কেকার ২.০ থেকে যেহেতু এইচটিটিপিট্রেসরোপোসিটরি রয়েছে (ট্রেসরোপোসিতোরির পরিবর্তে)
পিয়োটার চৌওয়ানিক

12

এই কোডটি আমার জন্য একটি স্প্রিং বুট অ্যাপ্লিকেশনটিতে কাজ করে - কেবল এটি ফিল্টার হিসাবে নিবন্ধ করুন

    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.util.Collection;
    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.Locale;
    import java.util.Map;
    import javax.servlet.*;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.commons.io.output.TeeOutputStream;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;

    @Component
    public class HttpLoggingFilter implements Filter {

        private static final Logger log = LoggerFactory.getLogger(HttpLoggingFilter.class);

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                             FilterChain chain) throws IOException, ServletException {
            try {
                HttpServletRequest httpServletRequest = (HttpServletRequest) request;
                HttpServletResponse httpServletResponse = (HttpServletResponse) response;

                Map<String, String> requestMap = this
                        .getTypesafeRequestMap(httpServletRequest);
                BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(
                        httpServletRequest);
                BufferedResponseWrapper bufferedResponse = new BufferedResponseWrapper(
                        httpServletResponse);

                final StringBuilder logMessage = new StringBuilder(
                        "REST Request - ").append("[HTTP METHOD:")
                        .append(httpServletRequest.getMethod())
                        .append("] [PATH INFO:")
                        .append(httpServletRequest.getServletPath())
                        .append("] [REQUEST PARAMETERS:").append(requestMap)
                        .append("] [REQUEST BODY:")
                        .append(bufferedRequest.getRequestBody())
                        .append("] [REMOTE ADDRESS:")
                        .append(httpServletRequest.getRemoteAddr()).append("]");

                chain.doFilter(bufferedRequest, bufferedResponse);
                logMessage.append(" [RESPONSE:")
                        .append(bufferedResponse.getContent()).append("]");
                log.debug(logMessage.toString());
            } catch (Throwable a) {
                log.error(a.getMessage());
            }
        }

        private Map<String, String> getTypesafeRequestMap(HttpServletRequest request) {
            Map<String, String> typesafeRequestMap = new HashMap<String, String>();
            Enumeration<?> requestParamNames = request.getParameterNames();
            while (requestParamNames.hasMoreElements()) {
                String requestParamName = (String) requestParamNames.nextElement();
                String requestParamValue;
                if (requestParamName.equalsIgnoreCase("password")) {
                    requestParamValue = "********";
                } else {
                    requestParamValue = request.getParameter(requestParamName);
                }
                typesafeRequestMap.put(requestParamName, requestParamValue);
            }
            return typesafeRequestMap;
        }

        @Override
        public void destroy() {
        }

        private static final class BufferedRequestWrapper extends
                HttpServletRequestWrapper {

            private ByteArrayInputStream bais = null;
            private ByteArrayOutputStream baos = null;
            private BufferedServletInputStream bsis = null;
            private byte[] buffer = null;

            public BufferedRequestWrapper(HttpServletRequest req)
                    throws IOException {
                super(req);
                // Read InputStream and store its content in a buffer.
                InputStream is = req.getInputStream();
                this.baos = new ByteArrayOutputStream();
                byte buf[] = new byte[1024];
                int read;
                while ((read = is.read(buf)) > 0) {
                    this.baos.write(buf, 0, read);
                }
                this.buffer = this.baos.toByteArray();
            }

            @Override
            public ServletInputStream getInputStream() {
                this.bais = new ByteArrayInputStream(this.buffer);
                this.bsis = new BufferedServletInputStream(this.bais);
                return this.bsis;
            }

            String getRequestBody() throws IOException {
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        this.getInputStream()));
                String line = null;
                StringBuilder inputBuffer = new StringBuilder();
                do {
                    line = reader.readLine();
                    if (null != line) {
                        inputBuffer.append(line.trim());
                    }
                } while (line != null);
                reader.close();
                return inputBuffer.toString().trim();
            }

        }

        private static final class BufferedServletInputStream extends
                ServletInputStream {

            private ByteArrayInputStream bais;

            public BufferedServletInputStream(ByteArrayInputStream bais) {
                this.bais = bais;
            }

            @Override
            public int available() {
                return this.bais.available();
            }

            @Override
            public int read() {
                return this.bais.read();
            }

            @Override
            public int read(byte[] buf, int off, int len) {
                return this.bais.read(buf, off, len);
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return true;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        }

        public class TeeServletOutputStream extends ServletOutputStream {

            private final TeeOutputStream targetStream;

            public TeeServletOutputStream(OutputStream one, OutputStream two) {
                targetStream = new TeeOutputStream(one, two);
            }

            @Override
            public void write(int arg0) throws IOException {
                this.targetStream.write(arg0);
            }

            public void flush() throws IOException {
                super.flush();
                this.targetStream.flush();
            }

            public void close() throws IOException {
                super.close();
                this.targetStream.close();
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setWriteListener(WriteListener writeListener) {

            }
        }

        public class BufferedResponseWrapper implements HttpServletResponse {

            HttpServletResponse original;
            TeeServletOutputStream tee;
            ByteArrayOutputStream bos;

            public BufferedResponseWrapper(HttpServletResponse response) {
                original = response;
            }

            public String getContent() {
                return bos.toString();
            }

            public PrintWriter getWriter() throws IOException {
                return original.getWriter();
            }

            public ServletOutputStream getOutputStream() throws IOException {
                if (tee == null) {
                    bos = new ByteArrayOutputStream();
                    tee = new TeeServletOutputStream(original.getOutputStream(),
                            bos);
                }
                return tee;

            }

            @Override
            public String getCharacterEncoding() {
                return original.getCharacterEncoding();
            }

            @Override
            public String getContentType() {
                return original.getContentType();
            }

            @Override
            public void setCharacterEncoding(String charset) {
                original.setCharacterEncoding(charset);
            }

            @Override
            public void setContentLength(int len) {
                original.setContentLength(len);
            }

            @Override
            public void setContentLengthLong(long l) {
                original.setContentLengthLong(l);
            }

            @Override
            public void setContentType(String type) {
                original.setContentType(type);
            }

            @Override
            public void setBufferSize(int size) {
                original.setBufferSize(size);
            }

            @Override
            public int getBufferSize() {
                return original.getBufferSize();
            }

            @Override
            public void flushBuffer() throws IOException {
                tee.flush();
            }

            @Override
            public void resetBuffer() {
                original.resetBuffer();
            }

            @Override
            public boolean isCommitted() {
                return original.isCommitted();
            }

            @Override
            public void reset() {
                original.reset();
            }

            @Override
            public void setLocale(Locale loc) {
                original.setLocale(loc);
            }

            @Override
            public Locale getLocale() {
                return original.getLocale();
            }

            @Override
            public void addCookie(Cookie cookie) {
                original.addCookie(cookie);
            }

            @Override
            public boolean containsHeader(String name) {
                return original.containsHeader(name);
            }

            @Override
            public String encodeURL(String url) {
                return original.encodeURL(url);
            }

            @Override
            public String encodeRedirectURL(String url) {
                return original.encodeRedirectURL(url);
            }

            @SuppressWarnings("deprecation")
            @Override
            public String encodeUrl(String url) {
                return original.encodeUrl(url);
            }

            @SuppressWarnings("deprecation")
            @Override
            public String encodeRedirectUrl(String url) {
                return original.encodeRedirectUrl(url);
            }

            @Override
            public void sendError(int sc, String msg) throws IOException {
                original.sendError(sc, msg);
            }

            @Override
            public void sendError(int sc) throws IOException {
                original.sendError(sc);
            }

            @Override
            public void sendRedirect(String location) throws IOException {
                original.sendRedirect(location);
            }

            @Override
            public void setDateHeader(String name, long date) {
                original.setDateHeader(name, date);
            }

            @Override
            public void addDateHeader(String name, long date) {
                original.addDateHeader(name, date);
            }

            @Override
            public void setHeader(String name, String value) {
                original.setHeader(name, value);
            }

            @Override
            public void addHeader(String name, String value) {
                original.addHeader(name, value);
            }

            @Override
            public void setIntHeader(String name, int value) {
                original.setIntHeader(name, value);
            }

            @Override
            public void addIntHeader(String name, int value) {
                original.addIntHeader(name, value);
            }

            @Override
            public void setStatus(int sc) {
                original.setStatus(sc);
            }

            @SuppressWarnings("deprecation")
            @Override
            public void setStatus(int sc, String sm) {
                original.setStatus(sc, sm);
            }

            @Override
            public String getHeader(String arg0) {
                return original.getHeader(arg0);
            }

            @Override
            public Collection<String> getHeaderNames() {
                return original.getHeaderNames();
            }

            @Override
            public Collection<String> getHeaders(String arg0) {
                return original.getHeaders(arg0);
            }

            @Override
            public int getStatus() {
                return original.getStatus();
            }

        }
    }

প্রতিক্রিয়া লগিংয়ের জন্য এটি ভাল কাজ করে - যদিও আমাকে লগ করা বাইটের সংখ্যার উপর একটি সীমা রাখতে হয়েছিল অন্যথায় এটি ইন্টেলিজ লগিং কনসোল আউটপুটকে ট্র্যাস করে।
আদম

স্ট্রিং গেটকন্টেন্ট () {if (bos == নাল) {স্ট্রিং.ফর্ম্যাট ("% s খুব তাড়াতাড়ি বলা হয়", বাফারড্রেসপনস্রাপার.ক্লাস.জেট ক্যানোনিক্যালনাম ()) ফেরান; } বাইট [] বাইটস = bos.toByteArray (); নতুন স্ট্রিং (Arrays.copyOf (বাইটস, 5000)) রিটার্ন করুন + "...."; }
আদম

লগিংয়ের আশেপাশে একটি "লগ.আইসট্রেসএনেবল ()" স্যুইচ লাগানোও মূল্যবান।
অ্যাডাম

6
জাভা যদি HTTPServletResponse এ কিছু ডিফল্ট পদ্ধতি যুক্ত করে থাকে তবে আমাদের এত বিশাল বাস্তবায়ন লেখার দরকার পড়বে না cool
অ্যাডাম

1
প্লাস ওয়ান আমদানি বিবৃতি অন্তর্ভুক্ত করার জন্য
গ্রানাডা কোডার

7

এখানে আমার সমাধান (বসন্ত 2.0.x)

মাভেন নির্ভরতা যুক্ত করুন:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

অ্যাপ্লিকেশন.সম্পাদনা সম্পাদনা করুন এবং নিম্নলিখিত লাইন যুক্ত করুন:

management.endpoints.web.exposure.include=* 

একবার আপনার বসন্ত বুট অ্যাপ্লিকেশন শুরু হয়ে গেলে আপনি এই ইউআরএলকে কল করে সর্বশেষ 100 টি HTTP অনুরোধগুলি ট্র্যাক করতে পারবেন: http: // লোকালহস্ত: 8070 / অ্যাকিউয়েটার / https


7

অনুরোধ এবং প্রতিক্রিয়াগুলির লগগুলি পেতে বর্তমানে স্প্রিং বুটে অ্যাকুয়েটর বৈশিষ্ট্য রয়েছে।

তবে আপনি অ্যাসপেক্ট (এওপি) ব্যবহার করে লগগুলিও পেতে পারেন।

: অ্যাসপেক্ট মত টীকা সাথে আপনি উপলব্ধ @Before, @AfterReturning, @AfterThrowingইত্যাদি

@Beforeঅনুরোধটি @AfterReturningলগ করে, প্রতিক্রিয়াটি @AfterThrowingলগ করে এবং ত্রুটি বার্তার লগ করে, আপনার সমস্ত শেষ পয়েন্টের লগের প্রয়োজন নাও হতে পারে, তাই আপনি প্যাকেজগুলিতে কিছু ফিল্টার প্রয়োগ করতে পারেন।

এখানে কয়েকটি উদাহরণ দেওয়া হল :

অনুরোধের জন্য:

@Before("within(your.package.where.endpoints.are..*)")
    public void endpointBefore(JoinPoint p) {
        if (log.isTraceEnabled()) {
            log.trace(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " START");
            Object[] signatureArgs = p.getArgs();


            ObjectMapper mapper = new ObjectMapper();
            mapper.enable(SerializationFeature.INDENT_OUTPUT);
            try {

                if (signatureArgs[0] != null) {
                    log.trace("\nRequest object: \n" + mapper.writeValueAsString(signatureArgs[0]));
                }
            } catch (JsonProcessingException e) {
            }
        }
    }

এখানে @Before("within(your.package.where.endpoints.are..*)")প্যাকেজ পাথ রয়েছে। এই প্যাকেজের মধ্যে থাকা সমস্ত শেষ পয়েন্টগুলি লগ তৈরি করবে।

প্রতিক্রিয়া জন্য:

@AfterReturning(value = ("within(your.package.where.endpoints.are..*)"),
            returning = "returnValue")
    public void endpointAfterReturning(JoinPoint p, Object returnValue) {
        if (log.isTraceEnabled()) {
            ObjectMapper mapper = new ObjectMapper();
            mapper.enable(SerializationFeature.INDENT_OUTPUT);
            try {
                log.trace("\nResponse object: \n" + mapper.writeValueAsString(returnValue));
            } catch (JsonProcessingException e) {
                System.out.println(e.getMessage());
            }
            log.trace(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " END");
        }
    }

এখানে @AfterReturning("within(your.package.where.endpoints.are..*)")প্যাকেজ পাথ রয়েছে। এই প্যাকেজের মধ্যে থাকা সমস্ত শেষ পয়েন্টগুলি লগ তৈরি করবে। এছাড়াও Object returnValueপ্রতিক্রিয়া রয়েছে।

ব্যতিক্রম:

@AfterThrowing(pointcut = ("within(your.package.where.endpoints.are..*)"), throwing = "e")
public void endpointAfterThrowing(JoinPoint p, Exception e) throws DmoneyException {
    if (log.isTraceEnabled()) {
        System.out.println(e.getMessage());

        e.printStackTrace();


        log.error(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " " + e.getMessage());
    }
}

এখানে @AfterThrowing(pointcut = ("within(your.package.where.endpoints.are..*)"), throwing = "e") প্যাকেজ পাথ রয়েছে। এই প্যাকেজের মধ্যে থাকা সমস্ত শেষ পয়েন্টগুলি লগ তৈরি করবে। এছাড়াও Exception eত্রুটি প্রতিক্রিয়া রয়েছে।

এখানে পুরো কোডটি রয়েছে:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Order(1)
@Component
@ConditionalOnExpression("${endpoint.aspect.enabled:true}")
public class EndpointAspect {
    static Logger log = Logger.getLogger(EndpointAspect.class);

    @Before("within(your.package.where.is.endpoint..*)")
    public void endpointBefore(JoinPoint p) {
        if (log.isTraceEnabled()) {
            log.trace(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " START");
            Object[] signatureArgs = p.getArgs();


            ObjectMapper mapper = new ObjectMapper();
            mapper.enable(SerializationFeature.INDENT_OUTPUT);
            try {

                if (signatureArgs[0] != null) {
                    log.trace("\nRequest object: \n" + mapper.writeValueAsString(signatureArgs[0]));
                }
            } catch (JsonProcessingException e) {
            }
        }
    }

    @AfterReturning(value = ("within(your.package.where.is.endpoint..*)"),
            returning = "returnValue")
    public void endpointAfterReturning(JoinPoint p, Object returnValue) {
        if (log.isTraceEnabled()) {
            ObjectMapper mapper = new ObjectMapper();
            mapper.enable(SerializationFeature.INDENT_OUTPUT);
            try {
                log.trace("\nResponse object: \n" + mapper.writeValueAsString(returnValue));
            } catch (JsonProcessingException e) {
                System.out.println(e.getMessage());
            }
            log.trace(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " END");
        }
    }


    @AfterThrowing(pointcut = ("within(your.package.where.is.endpoint..*)"), throwing = "e")
    public void endpointAfterThrowing(JoinPoint p, Exception e) throws Exception {
        if (log.isTraceEnabled()) {
            System.out.println(e.getMessage());

            e.printStackTrace();


            log.error(p.getTarget().getClass().getSimpleName() + " " + p.getSignature().getName() + " " + e.getMessage());
        }
    }
}

এখানে, @ConditionalOnExpression("${endpoint.aspect.enabled:true}")আপনি লগ সক্ষম / অক্ষম করতে পারেন ব্যবহার করে । শুধু যোগ endpoint.aspect.enabled:trueকরুন application.propertyএবং লগ নিয়ন্ত্রণ করুন

এওপি সম্পর্কে আরও তথ্য এখানে দেখুন:

এওপি সম্পর্কে স্প্রিং ডক্স

এওপি সম্পর্কে নমুনা নিবন্ধ


1
new ObjectMapper()ব্যয়বহুল, সবার জন্য আরও ভালভাবে একটি ম্যাপার ভাগ করুন
স্যাম

হ্যা অবশ্যই. এটি ডেমো কোড। উত্পাদনে আমাদের সেরা অনুশীলনগুলি অনুসরণ করতে হবে।
মোঃ সাজেদুল করিম

5

HandlerInterceptorAdapterকেবলমাত্র প্রাক-কেবল / কেবলমাত্র পোস্ট ইন্টারসেপ্টরগুলির সরলীকৃত বাস্তবায়নের জন্য আপনি একটি কাস্টম স্প্রিং ইন্টারসেপ্টরটিও কনফিগার করতে পারেন :

@Component
public class CustomHttpInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle (final HttpServletRequest request, final HttpServletResponse response,
            final Object handler)
            throws Exception {

        // Logs here

        return super.preHandle(request, response, handler);
    }

    @Override
    public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response,
            final Object handler, final Exception ex) {
        // Logs here
    }
}

তারপরে, আপনি যতগুলি ইন্টারসেপ্টর চান তার নিবন্ধ করুন:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    CustomHttpInterceptor customHttpInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(customHttpInterceptor).addPathPatterns("/endpoints");
    }

}

দ্রষ্টব্য: ঠিক যেমন @ রবার্টের বক্তব্য অনুসারে , আপনাকে এর নির্দিষ্ট প্রয়োগগুলি এবং আপনার অ্যাপ্লিকেশনটি ব্যবহার করছে সেদিকে মনোযোগ দিতে হবে HttpServletRequestHttpServletResponse

উদাহরণস্বরূপ, অ্যাপ্লিকেশনগুলি ব্যবহার করার জন্য ShallowEtagHeaderFilter, প্রতিক্রিয়া বাস্তবায়ন হবে একটি ContentCachingResponseWrapper, তাই আপনি যা করতে চান:

@Component
public class CustomHttpInterceptor extends HandlerInterceptorAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomHttpInterceptor.class);

    private static final int MAX_PAYLOAD_LENGTH = 1000;

    @Override
    public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response,
            final Object handler, final Exception ex) {
        final byte[] contentAsByteArray = ((ContentCachingResponseWrapper) response).getContentAsByteArray();

        LOGGER.info("Request body:\n" + getContentAsString(contentAsByteArray, response.getCharacterEncoding()));
    }

    private String getContentAsString(byte[] buf, String charsetName) {
        if (buf == null || buf.length == 0) {
            return "";
        }

        try {
            int length = Math.min(buf.length, MAX_PAYLOAD_LENGTH);

            return new String(buf, 0, length, charsetName);
        } catch (UnsupportedEncodingException ex) {
            return "Unsupported Encoding";
        }
    }

}

4

@ হানের উত্তরের জন্য এটি আমার পক্ষে কাজ করার জন্য কিছুটা পরিবর্তন প্রয়োজন, তবে এটি এখন পর্যন্ত সর্বাধিক অনুকূলিতকরণযোগ্য জিনিস।

এটি আমার পক্ষে কার্যকর হয়নি, সম্ভবত আমার কাছে একটি হ্যান্ডলারআইন্টারসেপ্টর অ্যাডাপ্টারও আছে [??] তবে আমি সেই সংস্করণটিতে সার্ভারের কাছ থেকে খারাপ প্রতিক্রিয়া পেতে থাকি। এটি আমার পরিবর্তন এখানে।

public class LoggableDispatcherServlet extends DispatcherServlet {

    private final Log logger = LogFactory.getLog(getClass());

    @Override
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

        long startTime = System.currentTimeMillis();
        try {
            super.doDispatch(request, response);
        } finally {
            log(new ContentCachingRequestWrapper(request), new ContentCachingResponseWrapper(response),
                    System.currentTimeMillis() - startTime);
        }
    }

    private void log(HttpServletRequest requestToCache, HttpServletResponse responseToCache, long timeTaken) {
        int status = responseToCache.getStatus();
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("httpStatus", status);
        jsonObject.addProperty("path", requestToCache.getRequestURI());
        jsonObject.addProperty("httpMethod", requestToCache.getMethod());
        jsonObject.addProperty("timeTakenMs", timeTaken);
        jsonObject.addProperty("clientIP", requestToCache.getRemoteAddr());
        if (status > 299) {
            String requestBody = null;
            try {
                requestBody = requestToCache.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
            } catch (IOException e) {
                e.printStackTrace();
            }
            jsonObject.addProperty("requestBody", requestBody);
            jsonObject.addProperty("requestParams", requestToCache.getQueryString());
            jsonObject.addProperty("tokenExpiringHeader",
                    responseToCache.getHeader(ResponseHeaderModifierInterceptor.HEADER_TOKEN_EXPIRING));
        }
        logger.info(jsonObject);
    }
}

আপনার অ্যাপ্লিকেশন যুদ্ধ বা জার হিসাবে প্যাকেজ হয়? আমি java.io.FileNotFoundException ত্রুটিটি পেতে থাকি: সার্লেটলেট কনটেক্সট রিসোর্সটি খুলতে পারেনি [/ WEB-INF / ব্লগিংডিসপাচার সার্ভেল-সার্লেট.এক্সএমএল]
মায়াঙ্ক মাধব

4

যদি এখনও কারও কারও এটির প্রয়োজন হয় তবে এটি হ'ল স্প্রিং এইচটিপিট্রেস অ্যাকুয়েটরের সাথে সাধারণ প্রয়োগ। কিন্তু তারা উপরেরটি বলেছে যে এটি মৃতদেহ লগ করে না।

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.boot.actuate.trace.http.HttpTrace;
import org.springframework.boot.actuate.trace.http.InMemoryHttpTraceRepository;
import org.springframework.stereotype.Repository;

@Slf4j
@Repository
public class LoggingInMemoryHttpTraceRepository extends InMemoryHttpTraceRepository {
    public void add(HttpTrace trace) {
        super.add(trace);
        log.info("Trace:" + ToStringBuilder.reflectionToString(trace));
        log.info("Request:" + ToStringBuilder.reflectionToString(trace.getRequest()));
        log.info("Response:" + ToStringBuilder.reflectionToString(trace.getResponse()));
    }
}

4

প্রকৃত উত্তরের জন্য দয়া করে নীচের লিঙ্কটি দেখুন https://gist.github.com/int128/e47217bebdb4c402b2ffa7cc199307ba

উপরে উল্লিখিত সমাধান থেকে কিছু পরিবর্তন করা হয়েছে, লগারের স্তর তথ্য থাকলে অনুরোধ এবং প্রতিক্রিয়া কনসোলে এবং ফাইলে লগ ইন করবে। আমরা কনসোল বা ফাইলের মধ্যে মুদ্রণ করতে পারেন।

@Component
public class LoggingFilter extends OncePerRequestFilter {

private static final List<MediaType> VISIBLE_TYPES = Arrays.asList(
        MediaType.valueOf("text/*"),
        MediaType.APPLICATION_FORM_URLENCODED,
        MediaType.APPLICATION_JSON,
        MediaType.APPLICATION_XML,
        MediaType.valueOf("application/*+json"),
        MediaType.valueOf("application/*+xml"),
        MediaType.MULTIPART_FORM_DATA
        );
Logger log = LoggerFactory.getLogger(ReqAndResLoggingFilter.class);
private static final Path path = Paths.get("/home/ramesh/loggerReq.txt");
private static BufferedWriter writer = null;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    try {
        writer = Files.newBufferedWriter(path, Charset.forName("UTF-8"));
    if (isAsyncDispatch(request)) {
        filterChain.doFilter(request, response);
    } else {
        doFilterWrapped(wrapRequest(request), wrapResponse(response), filterChain);
    }
    }finally {
        writer.close();
    }
}

protected void doFilterWrapped(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response, FilterChain filterChain) throws ServletException, IOException {
    try {
        beforeRequest(request, response);
        filterChain.doFilter(request, response);
    }
    finally {
        afterRequest(request, response);
        response.copyBodyToResponse();
    }
}

protected void beforeRequest(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) throws IOException {
    if (log.isInfoEnabled()) {
        logRequestHeader(request, request.getRemoteAddr() + "|>");
    }
}

protected void afterRequest(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) throws IOException {
    if (log.isInfoEnabled()) {
        logRequestBody(request, request.getRemoteAddr() + "|>");
        logResponse(response, request.getRemoteAddr() + "|<");
    }
}

private void logRequestHeader(ContentCachingRequestWrapper request, String prefix) throws IOException {
    String queryString = request.getQueryString();
    if (queryString == null) {
        printLines(prefix,request.getMethod(),request.getRequestURI());
        log.info("{} {} {}", prefix, request.getMethod(), request.getRequestURI());
    } else {
        printLines(prefix,request.getMethod(),request.getRequestURI(),queryString);
        log.info("{} {} {}?{}", prefix, request.getMethod(), request.getRequestURI(), queryString);
    }
    Collections.list(request.getHeaderNames()).forEach(headerName ->
    Collections.list(request.getHeaders(headerName)).forEach(headerValue ->
    log.info("{} {}: {}", prefix, headerName, headerValue)));
    printLines(prefix);
    printLines(RequestContextHolder.currentRequestAttributes().getSessionId());
    log.info("{}", prefix);

    log.info(" Session ID: ", RequestContextHolder.currentRequestAttributes().getSessionId());
}

private void printLines(String ...args) throws IOException {

    try {
    for(String varArgs:args) {
            writer.write(varArgs);
            writer.newLine();
    }
        }catch(IOException ex){
            ex.printStackTrace();
    }

}

private void logRequestBody(ContentCachingRequestWrapper request, String prefix) {
    byte[] content = request.getContentAsByteArray();
    if (content.length > 0) {
        logContent(content, request.getContentType(), request.getCharacterEncoding(), prefix);
    }
}

private void logResponse(ContentCachingResponseWrapper response, String prefix) throws IOException {
    int status = response.getStatus();
    printLines(prefix, String.valueOf(status), HttpStatus.valueOf(status).getReasonPhrase());
    log.info("{} {} {}", prefix, status, HttpStatus.valueOf(status).getReasonPhrase());
    response.getHeaderNames().forEach(headerName ->
    response.getHeaders(headerName).forEach(headerValue ->
    log.info("{} {}: {}", prefix, headerName, headerValue)));
    printLines(prefix);
    log.info("{}", prefix);
    byte[] content = response.getContentAsByteArray();
    if (content.length > 0) {
        logContent(content, response.getContentType(), response.getCharacterEncoding(), prefix);
    }
}

private void logContent(byte[] content, String contentType, String contentEncoding, String prefix) {
    MediaType mediaType = MediaType.valueOf(contentType);
    boolean visible = VISIBLE_TYPES.stream().anyMatch(visibleType -> visibleType.includes(mediaType));
    if (visible) {
        try {
            String contentString = new String(content, contentEncoding);
            Stream.of(contentString.split("\r\n|\r|\n")).forEach(line -> {
                try {
                    printLines(line);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            });
//              log.info("{} {}", prefix, line));
        } catch (UnsupportedEncodingException e) {
            log.info("{} [{} bytes content]", prefix, content.length);
        }
    } else {

        log.info("{} [{} bytes content]", prefix, content.length);
    }
}

private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) {
    if (request instanceof ContentCachingRequestWrapper) {
        return (ContentCachingRequestWrapper) request;
    } else {
        return new ContentCachingRequestWrapper(request);
    }
}

private static ContentCachingResponseWrapper wrapResponse(HttpServletResponse response) {
    if (response instanceof ContentCachingResponseWrapper) {
        return (ContentCachingResponseWrapper) response;
    } else {
        return new ContentCachingResponseWrapper(response);
    }
}
} 

ফাইলে আউটপুট:

127.0.0.1|>
POST
/createUser
127.0.0.1|>
session Id:C0793464532E7F0C7154913CBA018B2B
Request:
{
  "name": "asdasdas",
  "birthDate": "2018-06-21T17:11:15.679+0000"
}
127.0.0.1|<
200
OK
127.0.0.1|<
Response:
{"name":"asdasdas","birthDate":"2018-06-21T17:11:15.679+0000","id":4}

1
দুর্দান্ত উত্তর, কেবলমাত্র প্রস্তাবটি হ'ল বাফারে সমস্ত আউটপুট সংগ্রহ করা এবং একক বিবৃতিতে লগইন করা।
মাইক 13

2

যদি আপনি কেবল আপনার অনুরোধ পেলোডের অংশ দেখতে পাচ্ছেন, তবে আপনার অনুরোধের বডিটিতে setMaxPayloadLengthকেবল 50 টি অক্ষর দেখানোর ক্ষেত্রে এটি ডিফল্ট হিসাবে আপনাকে ফাংশনটি কল করতে হবে। এছাড়াও, setIncludeHeadersমিথ্যাতে সেট করা ভাল ধারণা যদি আপনি নিজের লেখকের শিরোনাম লগ করতে না চান!

@Bean
public CommonsRequestLoggingFilter requestLoggingFilter() {
    CommonsRequestLoggingFilter loggingFilter = new CommonsRequestLoggingFilter();
    loggingFilter.setIncludeClientInfo(false);
    loggingFilter.setIncludeQueryString(false);
    loggingFilter.setIncludePayload(true);
    loggingFilter.setIncludeHeaders(false);
    loggingFilter.setMaxPayloadLength(500);
    return loggingFilter;
}

আমি এটি বসন্তের এমভিসিতে ব্যবহার করার চেষ্টা করছি এবং এটি আমার পক্ষে কাজ করছে না, এই শিমটি নিবন্ধন করা এবং লগার যুক্ত করা ছাড়া কোনও অতিরিক্ত বিন্যাস প্রয়োজন?
নোমান আক্তার

1

আপনি যদি নিজের বুট অ্যাপে টমক্যাট ব্যবহার করেন তবে এটি আপনার org.apache.catalina.filters.RequestDumperFilterজন্য একটি শ্রেণির পথে path (তবে এটি আপনাকে "একক জায়গায় ব্যতিক্রম সহ" সরবরাহ করবে না)।


1

নীচে আটকানো কোডটি আমার পরীক্ষাগুলির সাথে কাজ করে এবং আমার [গিথুব প্রকল্প] [1] থেকে ডাউনলোড করা যায়, কোনও প্রোডাকশন প্রকল্পের উপর ভিত্তি করে সমাধান প্রয়োগের পরে ভাগ করে নেওয়া।

@Configuration
public class LoggingFilter extends GenericFilterBean {

    /**
     * It's important that you actually register your filter this way rather then just annotating it
     * as @Component as you need to be able to set for which "DispatcherType"s to enable the filter
     * (see point *1*)
     * 
     * @return
     */
    @Bean
    public FilterRegistrationBean<LoggingFilter> initFilter() {
        FilterRegistrationBean<LoggingFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new LoggingFilter());

        // *1* make sure you sett all dispatcher types if you want the filter to log upon
        registrationBean.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));

        // *2* this should put your filter above any other filter
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);

        return registrationBean;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        ContentCachingRequestWrapper wreq = 
            new ContentCachingRequestWrapper(
                (HttpServletRequest) request);

        ContentCachingResponseWrapper wres = 
            new ContentCachingResponseWrapper(
                (HttpServletResponse) response);

        try {

            // let it be ...
            chain.doFilter(wreq, wres);

            // makes sure that the input is read (e.g. in 404 it may not be)
            while (wreq.getInputStream().read() >= 0);

            System.out.printf("=== REQUEST%n%s%n=== end request%n",
                    new String(wreq.getContentAsByteArray()));

            // Do whatever logging you wish here, in this case I'm writing request 
            // and response to system out which is probably not what you wish to do
            System.out.printf("=== RESPONSE%n%s%n=== end response%n",
                    new String(wres.getContentAsByteArray()));

            // this is specific of the "ContentCachingResponseWrapper" we are relying on, 
            // make sure you call it after you read the content from the response
            wres.copyBodyToResponse();

            // One more point, in case of redirect this will be called twice! beware to handle that
            // somewhat

        } catch (Throwable t) {
            // Do whatever logging you whish here, too
            // here you should also be logging the error!!!
            throw t;
        }

    }
}

0

ইনপুট পরামিতি এবং বডি সহ সমস্ত অনুরোধগুলি লগ করার জন্য, আমরা ফিল্টার এবং ইন্টারসেপ্টর ব্যবহার করতে পারি । তবে ফিল্টার বা ইন্টারসেপ্টর ব্যবহার করার সময় আমরা অনুরোধের মূল অংশটি একাধিকবার মুদ্রণ করতে পারি না। আরও ভাল উপায় হ'ল আমরা বসন্ত-এওপি ব্যবহার করতে পারি। এটি ব্যবহার করে আমরা অ্যাপ্লিকেশন থেকে লগিং প্রক্রিয়াটি ডিকুয়াল করতে পারি। Aop লগিং ব্যবহার করা যেতে পারে ইনপুট এবং আউটপুট এর প্রতিটি পদ্ধতির অ্যাপ্লিকেশনে।

আমার সমাধানটি হ'ল:

 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
 import org.aspectj.lang.annotation.Pointcut;
 import org.aspectj.lang.reflect.CodeSignature;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 import com.fasterxml.jackson.databind.ObjectMapper;
 @Aspect
 @Component
public class LoggingAdvice {
private static final Logger logger = 
LoggerFactory.getLogger(LoggingAdvice.class);

//here we can provide any methodName, packageName, className 
@Pointcut(value = "execution(* com.package.name.*.*.*(..) )")
public void myPointcut() {

}

@Around("myPointcut()")
public Object applicationLogger(ProceedingJoinPoint pjt) throws Throwable {
    ObjectMapper mapper = new ObjectMapper();
    String methodName = pjt.getSignature().getName();
    String className = pjt.getTarget().getClass().toString();
    String inputParams = this.getInputArgs(pjt ,mapper);
    logger.info("method invoked from " + className + " : " + methodName + "--Request Payload::::"+inputParams);
    Object object = pjt.proceed();
    try {
        logger.info("Response Object---" + mapper.writeValueAsString(object));
    } catch (Exception e) {
    }
    return object;
}

private String getInputArgs(ProceedingJoinPoint pjt,ObjectMapper mapper) {
    Object[] array = pjt.getArgs();
    CodeSignature signature = (CodeSignature) pjt.getSignature();

    StringBuilder sb = new StringBuilder();
    sb.append("{");
    int i = 0;
    String[] parameterNames = signature.getParameterNames();
    int maxArgs = parameterNames.length;
    for (String name : signature.getParameterNames()) {
        sb.append("[").append(name).append(":");
        try {
            sb.append(mapper.writeValueAsString(array[i])).append("]");
            if(i != maxArgs -1 ) {
                sb.append(",");
            }
        } catch (Exception e) {
            sb.append("],");
        }
        i++;
    }
    return sb.append("}").toString();
}

}


0

আপনার যদি স্প্রিং বুট কনফিগার সার্ভারটি কনফিগার করা থাকে তবে কেবল শ্রেণীর জন্য ডিবাগ লগার সক্ষম করুন:

Http11InputBuffer.Http11InputBuffer.java

ডিবাগগুলি প্রতিটি অনুরোধের জন্য সমস্ত অনুরোধ এবং প্রতিক্রিয়াগুলিকে লগ করবে


-1

অনুরোধগুলি লগ করতে যাতে ফলাফল 400 হয়:

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.AbstractRequestLoggingFilter;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.WebUtils;

/**
 * Implementation is partially copied from {@link AbstractRequestLoggingFilter} and modified to output request information only if request resulted in 400.
 * Unfortunately {@link AbstractRequestLoggingFilter} is not smart enough to expose {@link HttpServletResponse} value in afterRequest() method.
 */
@Component
public class RequestLoggingFilter extends OncePerRequestFilter {

    public static final String DEFAULT_AFTER_MESSAGE_PREFIX = "After request [";

    public static final String DEFAULT_AFTER_MESSAGE_SUFFIX = "]";

    private final boolean includeQueryString = true;
    private final boolean includeClientInfo = true;
    private final boolean includeHeaders = true;
    private final boolean includePayload = true;

    private final int maxPayloadLength = (int) (2 * FileUtils.ONE_MB);

    private final String afterMessagePrefix = DEFAULT_AFTER_MESSAGE_PREFIX;

    private final String afterMessageSuffix = DEFAULT_AFTER_MESSAGE_SUFFIX;

    /**
     * The default value is "false" so that the filter may log a "before" message
     * at the start of request processing and an "after" message at the end from
     * when the last asynchronously dispatched thread is exiting.
     */
    @Override
    protected boolean shouldNotFilterAsyncDispatch() {
        return false;
    }

    @Override
    protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
            throws ServletException, IOException {

        final boolean isFirstRequest = !isAsyncDispatch(request);
        HttpServletRequest requestToUse = request;

        if (includePayload && isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
            requestToUse = new ContentCachingRequestWrapper(request, maxPayloadLength);
        }

        final boolean shouldLog = shouldLog(requestToUse);

        try {
            filterChain.doFilter(requestToUse, response);
        } finally {
            if (shouldLog && !isAsyncStarted(requestToUse)) {
                afterRequest(requestToUse, response, getAfterMessage(requestToUse));
            }
        }
    }

    private String getAfterMessage(final HttpServletRequest request) {
        return createMessage(request, this.afterMessagePrefix, this.afterMessageSuffix);
    }

    private String createMessage(final HttpServletRequest request, final String prefix, final String suffix) {
        final StringBuilder msg = new StringBuilder();
        msg.append(prefix);
        msg.append("uri=").append(request.getRequestURI());

        if (includeQueryString) {
            final String queryString = request.getQueryString();
            if (queryString != null) {
                msg.append('?').append(queryString);
            }
        }

        if (includeClientInfo) {
            final String client = request.getRemoteAddr();
            if (StringUtils.hasLength(client)) {
                msg.append(";client=").append(client);
            }
            final HttpSession session = request.getSession(false);
            if (session != null) {
                msg.append(";session=").append(session.getId());
            }
            final String user = request.getRemoteUser();
            if (user != null) {
                msg.append(";user=").append(user);
            }
        }

        if (includeHeaders) {
            msg.append(";headers=").append(new ServletServerHttpRequest(request).getHeaders());
        }

        if (includeHeaders) {
            final ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
            if (wrapper != null) {
                final byte[] buf = wrapper.getContentAsByteArray();
                if (buf.length > 0) {
                    final int length = Math.min(buf.length, maxPayloadLength);
                    String payload;
                    try {
                        payload = new String(buf, 0, length, wrapper.getCharacterEncoding());
                    } catch (final UnsupportedEncodingException ex) {
                        payload = "[unknown]";
                    }
                    msg.append(";payload=").append(payload);
                }
            }
        }
        msg.append(suffix);
        return msg.toString();
    }

    private boolean shouldLog(final HttpServletRequest request) {
        return true;
    }

    private void afterRequest(final HttpServletRequest request, final HttpServletResponse response, final String message) {
        if (response.getStatus() == HttpStatus.BAD_REQUEST.value()) {
            logger.warn(message);
        }
    }

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.