Skip to content

Instantly share code, notes, and snippets.

@oswaldo
Last active June 27, 2017 16:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oswaldo/5f439061886b9aea6ea80536fe317b13 to your computer and use it in GitHub Desktop.
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._
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