How can I log each request/response using Alamofire?

IosDebuggingAfnetworking 2Alamofire

Ios Problem Overview


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.

Ios Solutions


Solution 1 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

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>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCosminView Question on Stackoverflow
Solution 1 - IosullstrmView Answer on Stackoverflow
Solution 2 - IosclozachView Answer on Stackoverflow
Solution 3 - Ios0xcedView Answer on Stackoverflow
Solution 4 - IosaliView Answer on Stackoverflow
Solution 5 - Iosvinbhai4uView Answer on Stackoverflow
Solution 6 - IosKaiser AblizView Answer on Stackoverflow
Solution 7 - IosMANISH PATHAKView Answer on Stackoverflow
Solution 8 - IosGenarView Answer on Stackoverflow
Solution 9 - IosAaoIiView Answer on Stackoverflow
Solution 10 - Iosandy0570View Answer on Stackoverflow