Last active
June 27, 2017 16:02
-
-
Save oswaldo/5f439061886b9aea6ea80536fe317b13 to your computer and use it in GitHub Desktop.
pure scala http calls with log messages for integration tests interested in the call duration (good to export to Kibana) just import HttpUtil._
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package httputil | |
import java.io.OutputStreamWriter | |
import com.typesafe.scalalogging.Logger | |
import org.slf4j.MDC | |
import scala.collection.JavaConverters._ | |
import java.util.UUID | |
import java.time.Instant | |
import java.time.Duration | |
import scala.util.Either | |
trait HttpOperations { | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
def get(url: String, | |
headers: Map[String, String] = Map.empty, | |
connectTimeout: Int, | |
readTimeout: Int): String | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
def post(url: String, | |
data: Option[String], | |
headers: Map[String, String], | |
connectTimeout: Int, | |
readTimeout: Int): String | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
def post(url: String, | |
data: String, | |
headers: Map[String, String] = Map.empty, | |
connectTimeout: Int, | |
readTimeout: Int): String | |
} | |
case class HttpCallParams(url: String, | |
requestMethod: String, | |
connectTimeout: Int, | |
readTimeout: Int, | |
data: Option[String] = None, | |
headers: Map[String, String] = Map.empty, | |
requestId: UUID = UUID.randomUUID, | |
timestamp: Instant = Instant.now) | |
case class HttpCallResponse(val requestTimestamp: Instant, | |
val outcome: Either[String, Exception]) | |
case class HttpUtil(timeout: Int = 60000) extends HttpOperations { | |
private def logMdc(params: HttpCallParams, | |
response: Option[HttpCallResponse] = None) = { | |
MDC.clear | |
val logger = Logger[HttpUtil] | |
val context = List( | |
"url" -> params.url, | |
"requestMethod" -> params.requestMethod, | |
"connectTimeout" -> params.connectTimeout.toString, | |
"readTimeout" -> params.readTimeout.toString, | |
"dataSize" -> params.data.getOrElse("").size.toString, | |
"headerCount" -> params.headers.size.toString, | |
"testRequestId" -> params.requestId.toString | |
) ++ response | |
.map( | |
response => | |
"beforeRequest" -> "false" | |
:: "elapsed" -> Duration | |
.between(response.requestTimestamp, Instant.now) | |
.toMillis | |
.toString | |
:: (response.outcome match { | |
case Left(response) => "responseData" -> response | |
case Right(exception) => "exceptionMessage" -> exception.getMessage | |
}) | |
:: Nil) | |
.getOrElse( | |
"beforeRequest" -> "true" | |
:: (if (params.data.isDefined && !response.isDefined) | |
"requestData" -> params.data.get :: Nil | |
else Nil)) | |
MDC.setContextMap(context.toMap.asJava) | |
// for ((key, value) <- params.headers) { | |
// MDC.put(s"header_$key", value) | |
// } | |
val message = | |
context.map { case (key, value) => s"$key: $value" }.mkString(", ") | |
response match { | |
case Some(HttpCallResponse(_, Right(e))) => { | |
logger.error(message, e) | |
MDC.clear | |
throw e | |
} | |
case _ => | |
logger.debug(message) | |
MDC.clear | |
} | |
} | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
def call(params: HttpCallParams): String = { | |
logMdc(params) | |
val start = Instant.now | |
try { | |
import java.net.{HttpURLConnection, URL} | |
val connection = | |
(new URL(params.url)).openConnection.asInstanceOf[HttpURLConnection] | |
connection.setConnectTimeout(params.connectTimeout) | |
connection.setReadTimeout(params.readTimeout) | |
connection.setRequestMethod(params.requestMethod) | |
for ((key, value) <- params.headers.toIterable) { | |
connection.setRequestProperty(key, value) | |
} | |
if (params.data.isDefined) { | |
connection.setDoOutput(true) | |
connection.connect | |
val wr = new OutputStreamWriter(connection.getOutputStream) | |
wr.write(params.data.get) | |
wr.flush | |
wr.close | |
} | |
val inputStream = connection.getInputStream | |
val content = io.Source.fromInputStream(inputStream).mkString | |
if (inputStream != null) inputStream.close | |
logMdc(params, Some(HttpCallResponse(start, Left(content)))) | |
content | |
} catch { | |
case e: Exception => { | |
logMdc(params, Some(HttpCallResponse(start, Right(e)))) | |
throw e | |
} | |
} | |
} | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
override def get(url: String, | |
headers: Map[String, String] = Map.empty, | |
connectTimeout: Int = timeout, | |
readTimeout: Int = timeout): String = | |
call( | |
HttpCallParams(url, "GET", connectTimeout, readTimeout, None, headers)) | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
override def post(url: String, | |
data: Option[String], | |
headers: Map[String, String], | |
connectTimeout: Int, | |
readTimeout: Int): String = | |
call( | |
HttpCallParams(url, "POST", connectTimeout, readTimeout, data, headers)) | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
override def post(url: String, | |
data: String, | |
headers: Map[String, String] = Map.empty, | |
connectTimeout: Int = timeout, | |
readTimeout: Int = timeout): String = | |
post(url, Option(data), headers, connectTimeout, readTimeout) | |
} | |
object HttpUtil extends HttpOperations { | |
private val instance = HttpUtil(60000) | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
override def get(url: String, | |
headers: Map[String, String] = Map.empty, | |
connectTimeout: Int = instance.timeout, | |
readTimeout: Int = instance.timeout): String = | |
instance.get(url, headers, connectTimeout, readTimeout) | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
override def post(url: String, | |
data: Option[String], | |
headers: Map[String, String], | |
connectTimeout: Int, | |
readTimeout: Int): String = | |
instance.post(url, data, headers, connectTimeout, readTimeout) | |
@throws(classOf[java.io.IOException]) | |
@throws(classOf[java.net.SocketTimeoutException]) | |
override def post(url: String, | |
data: String, | |
headers: Map[String, String] = Map.empty, | |
connectTimeout: Int = instance.timeout, | |
readTimeout: Int = instance.timeout): String = | |
instance.post(url, data, headers, connectTimeout, readTimeout) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment