'How can I log each request/response using Alamofire?

Is there a way to log each request / response using Alamofire (something similar to AFNetworkActivityLogger) ?

I am aware of Printable, DebugPrintable and Output (cURL) but they are not quite what I am looking for.



Solution 1:[1]

There's a sweet little pod for this: https://github.com/konkab/AlamofireNetworkActivityLogger

Add this to your podfile:

pod 'AlamofireNetworkActivityLogger', '~> 2.0'

In your AppDelegate:

import AlamofireNetworkActivityLogger

Then in your didFinishLaunchingWithOptions, add this:

NetworkActivityLogger.shared.level = .debug
NetworkActivityLogger.shared.startLogging()

EDIT: I've actually encountered crashes with this in production. To be on the safe side, use "build flags" to only use this in debug, something like this:

#if DEBUG
    NetworkActivityLogger.shared.level = .debug
    NetworkActivityLogger.shared.startLogging()
#endif

Solution 2:[2]

Something like this might be what you were looking for:

extension Request {
   public func debugLog() -> Self {
      #if DEBUG
         debugPrint(self)
      #endif
      return self
   }
}

Usage:

Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
         .debugLog()
         .response {…}

If you want to print all responses, you could write your own response method, similar to the responseObject() method at the top of this tutorial:

http://www.raywenderlich.com/87595/intermediate-alamofire-tutorial

[Update: added below per the request from @trauzti.]

Here's how one might do the responseObject() approach in order to print output on every request.

Caveat lector: I haven't personally tested this code, and would probably make different choices in production. This simply shows how the Wenderlich tutorial code can include debug logging. Also note: since the tutorial is pre-Swift 2.0, I've used the old println() instead of print().

@objc public protocol ResponseObjectSerializable {
  init(response: NSHTTPURLResponse, representation: AnyObject)
}

extension Alamofire.Request {
  public func responseObject<T: ResponseObjectSerializable>(completionHandler: (NSURLRequest, NSHTTPURLResponse?, T?, NSError?) -> Void) -> Self {
    let serializer: Serializer = { (request, response, data) in

      #if DEBUG
         println("Request: \(request.URL)")
      #endif

      let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
      let (JSON: AnyObject?, serializationError) = JSONSerializer(request, response, data)
      if response != nil && JSON != nil {
        #if DEBUG
           println("Response:")
           debugPrint(JSON)
        #endif

        return (T(response: response!, representation: JSON!), nil)
      } else {
        #if DEBUG
           println("Failed Serialization:")
           debugPrint(serializationError)
        #endif

        return (nil, serializationError)
      }
    }

    return response(serializer: serializer, completionHandler: { (request, response, object, error) in
      completionHandler(request, response, object as? T, error)
    })
  }
}

Solution 3:[3]

Since Alamofire 5, the easiest way is to define an EventMonitor subclass:

final class AlamofireLogger: EventMonitor {
    func requestDidResume(_ request: Request) {
        let body = request.request.flatMap { $0.httpBody.map { String(decoding: $0, as: UTF8.self) } } ?? "None"
        let message = """
        ?? Request Started: \(request)
        ?? Body Data: \(body)
        """
        NSLog(message)
    }

    func request<Value>(_ request: DataRequest, didParseResponse response: DataResponse<Value>) {
        NSLog("?? Response Received: \(response.debugDescription)")
    }
}

Then use it on your session:

let session = Session(eventMonitors: [ AlamofireLogger() ])

This sample code was adapted from https://github.com/Alamofire/Alamofire/issues/2867#issuecomment-509662892

Solution 4:[4]

Timberjack is what you are looking. Timberjack is a simple, unintrusive network activity logger. Log every request your app makes, or limit to only those using a certain NSURLSession if you’d prefer. It also works with Alamofire, if that’s your thing.

https://cocoapods.org/pods/Timberjack

usage:

import Alamofire
import Timberjack

class HTTPManager: Alamofire.Manager {
static let sharedManager: HTTPManager = {
    let configuration = Timberjack.defaultSessionConfiguration()
    let manager = HTTPManager(configuration: configuration)
    return manager
}()
}

Solution 5:[5]

Adding to above answer for Alamofire 4.0+ Swift 3

extension DataRequest {        
        public func LogRequest() -> Self {
        //Your logic for logging
        return self
    }
}

When Requesting

Alamofire.request(requestUrl, method: .post, parameters: parameter, encoding: JSONEncoding.default)
            .LogRequest()
            .responseJSON { response in
            //Do your thing
            }

If you want to cancel the request in any case(which was something I wanted) you can self.cancel() anywhere before you return self

Solution 6:[6]

in Alamofire 5 URLRequest is created asynchronously which means

extension Request {
 public func debugLog() -> Self {
  #if DEBUG
     debugPrint(self)
  #endif
  return self
  }
}

is not the best solution anymore. instead, calling cURLDescription is recommend as below:

let request = AF.request(<Your request>))
request.cURLDescription { (curl) in
   print("CURL \(curl)")
}
request.responseJSON { response in
   //Do something with your response...
}

or

extension Request {
public func debugLog() -> Self {
    #if DEBUG
    cURLDescription(calling: { (curl) in
        debugPrint("=======================================")
        print(curl)
        debugPrint("=======================================")
    })
    #endif
    return self
  }
 }

Solution 7:[7]

SOLUTION FOR SWIFT 3.0+

For Printing Request parameter and headers:

Alamofire.request(url, method: .get, parameters: parameters, headers: headers)
            .validate()
            .responseObject { (response: DataResponse<T>) in
                self.pendingRequests.removeValue(forKey: endPoint)
                completion!(response)

                if(NetworkConfig.loggingEnable) {
                    debugPrint("************* printing REQUEST parameter and Headers *************")
                    debugPrint("RESPONSE : \(response.debugDescription)")
                }
        }.responseDebugPrint()

For Printing Response . use below extension .

import Foundation
import Alamofire

extension Alamofire.DataRequest {
    func responseDebugPrint() -> Self {
        if NetworkConfig.loggingEnable {

            return responseJSON() {
                response in
                if let  JSON = response.result.value,
                    let JSONData = try? JSONSerialization.data(withJSONObject: JSON, options: .prettyPrinted),
                    let prettyString = NSString(data: JSONData, encoding: String.Encoding.utf8.rawValue) {
                    print(prettyString)
                } else if let error = response.result.error {
                    print("Error Debug Print: \(error.localizedDescription)")
                }
            }
        }
        return self
    }
}

Small gist for you : https://gist.github.com/manishpathak99/348f2eb0167c0ff6e12ecd667612bc9b/edit

Solution 8:[8]

In Alamofire 5.0.0 I used the answer based on: https://github.com/Alamofire/Alamofire/issues/2867#issuecomment-509662892 but I had to replace DataResponse by AFDataResponse. For example:

import Alamofire

final class AlamofireLogger: EventMonitor {

    func requestDidResume(_ request: Request) {

        let allHeaders = request.request.flatMap { $0.allHTTPHeaderFields.map { $0.description } } ?? "None"
        let headers = """
        ???????? Request Started: \(request)
        ???????? Headers: \(allHeaders)
        """
        NSLog(headers)


        let body = request.request.flatMap { $0.httpBody.map { String(decoding: $0, as: UTF8.self) } } ?? "None"
        let message = """
        ???????? Request Started: \(request)
        ???????? Body Data: \(body)
        """
        NSLog(message)
    }

    func request<Value>(_ request: DataRequest, didParseResponse response: AFDataResponse<Value>) {

        NSLog("???????? Response Received: \(response.debugDescription)")
        NSLog("???????? Response All Headers: \(String(describing: response.response?.allHeaderFields))")
    }
}

And then you can use it in the following way:

let session = Session(eventMonitors: [ AlamofireLogger() ])

As it has explained by 0xced in an aforementioned post.

Solution 9:[9]

In Alamofire 5 and above you can get curl request details by the below code:

request.cURLDescription(calling: { (curl) in
    print(curl)
})

And response/error data:

request.responseDecodable { (response:AFDataResponse<T>) in
            
            switch response.result {
            case .success(let value):
                
                var responseMessage : String?
                
                if let data = response.data {
                    let json = String(data: data, encoding: String.Encoding.utf8)
                    responseMessage = String(describing: json)
                }
                
                print(responseMessage)
                
                break;
                
            case .failure(let error):
                
                var message : String?
                
                if let data = response.data {
                    let json = String(data: data, encoding: String.Encoding.utf8)
                    message = String(describing: json)
                }
                
                print(message)
                
                break
            }
            
        }

Solution 10:[10]

Alamofire provides a powerful way to gain insight into all the internal events via the EventMonitor protocol. EventMonitor includes several Alamofire events such as URLSessionDelegate request events. This makes EventMonitor ideal for logging events.

import Alamofire

class NetworkLogger: EventMonitor {
  
  let queue = DispatchQueue(label: "com.company.project.networklogger")
  
  func requestDidFinish(_ request: Request) {
    print(request.description)
  }
  
  func request<Value>(
    _ request: DataRequest,
    didParseResponse response: DataResponse<Value, AFError>
  ) {
    guard let data = response.data else {
      return
    }
    if let json = try? JSONSerialization
      .jsonObject(with: data, options: .mutableContainers) {
        print(json)
    }
  }
}

Reference: https://www.raywenderlich.com/11668143-alamofire-tutorial-for-ios-advanced-usage#toc-anchor-004

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 0xced
Solution 4 ali
Solution 5 vinbhai4u
Solution 6
Solution 7
Solution 8 Genar
Solution 9 AaoIi
Solution 10 andy0570