This is code that handles pushing data to an analytics API, and IMO it feels too much like Java.
logActivity
is a method that uses Dispatch
to POST the data to this API. I am worried that an exception could occur and that is why I wrapped the methods in a try/catch
block. However, this feels very Javaesque.
Do I even need the try/catch
block? Can logActivity
method fail and cause the end point to stop working? Any better ways to do this?
def buyLinkAnalytics(notif: Notification, reqInfo: RequestInfo): Unit = {
try {
logActivity(buy_link_requested, Some(LoggedInAccount(AccountId(notif.emails.get.to._id))), notif.productId.get._id.toString, None, reqInfo)
} catch {
case e: Exception => {
log.error(e.toString)
}
}
}
def productShareAnalytics(notif:Notification, reqInfo:RequestInfo): Unit = {
try {
logActivity(product_shared, Some(LoggedInAccount(AccountId(notif.emails.get.to._id))), notif.productId.get._id.toString, None, reqInfo)
} catch {
case e: Exception => {
log.error(e.toString)
}
}
}
def welcomeAnalytics(notif:Notification, reqInfo:RequestInfo): Unit = {
val uri = reqInfo.stripedUri
try {
logActivity(welcome, Some(LoggedInAccount(notif.accounts.get.from.get)), uri, None, reqInfo)
} catch {
case e: Exception => {
log.error(e.toString)
}
}
}
def myCatalogAnalytics(notif:Notification, reqInfo:RequestInfo): Unit = {
val uri = reqInfo.stripedUri
try {
logActivity(welcome, Some(LoggedInAccount(notif.accounts.get.from.get)), uri, None, reqInfo)
} catch {
case e: Exception => {
log.error(e.toString)
}
}
}
def handleAnalytics(notif:Notification, reqInfo:RequestInfo) {
notif.notification match {
case BuyProduct => buyLinkAnalytics(notif, reqInfo)
case ProductShare => productShareAnalytics(notif, reqInfo)
case Welcome => welcomeAnalytics(notif, reqInfo)
case MyCatalog => myCatalogAnalytics(notif, reqInfo)
case _ => log.debug("Notification Type not found. Nothing put into analytics")
}
}
def sendActivityLog[A] (account_id: String, activityLog: A, authParams: Map[String, String] = Map.empty[String, String], endpoint: String)(implicit fmt: Format[A]) = {
val activityLogJson = Json.stringify (Json.toJson (activityLog))
val scv = url(s"${config.getString("activity_log.url")}$endpoint/$account_id?key=wc_analytics") << activityLogJson <:< Map("Content-Type" -> "application/json") <:< authParams
logger.debug(s"LOGGED: ${scv.url} << $activityLogJson")
Http (scv OK as.String)
}
def logActivity (
action : String,
visitor : Option[Visitor],
uri : String,
target_id : Option[String],
requestInfo : RequestInfo,
context : String = "-") = {
import core.security.AppId.WcApp
// In theory, no loggable business event should ever occur without an AppId.
// But default to WC if we have to.
val appId = requestInfo.appId.getOrElse (WcApp)._id
val authParams = findAuthParams(requestInfo)
if (visitor == None) {
sendActivityLog ("None", ActivityLog (appId, action, uri, "-", context), authParams, activity_account)
}
visitor.foreach {
case LoggedInAccountWithOther (account_id, other_id) =>
sendActivityLog (
account_id._id,
ActivityLog (
appId,
action,
uri,
target_id.getOrElse (other_id._id),
context
),
authParams,
activity_account
)
case v =>
sendActivityLog (v.accountId._id, ActivityLog (appId, action, uri, "-", context), authParams, activity_account)
}
}
1 Answer 1
If you think that those try/catch blocks look too verbose, then you can create utility method like:
def logExceptions[R](body: => R): R =
try { body }
catch {
case e: Exception => log.error(e.toString)
}
Then rewrite your code like:
def buyLinkAnalytics(notif: Notification, reqInfo: RequestInfo) {
logExceptions {
logActivity(buy_link_requested, Some(LoggedInAccount(AccountId(notif.emails.get.to._id))), notif.productId.get._id.toString, None, reqInfo)
}
}
def productShareAnalytics(notif:Notification, reqInfo:RequestInfo) {
logExceptions {
logActivity(product_shared, Some(LoggedInAccount(AccountId(notif.emails.get.to._id))), notif.productId.get._id.toString, None, reqInfo)
}
}
...