Skip to content
This repository has been archived by the owner on Jun 4, 2021. It is now read-only.

Commit

Permalink
Added ua-parser enrichment (closes snowplow/snowplow#62)
Browse files Browse the repository at this point in the history
Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)

Added ua-parser enrichment (closes snowplow/snowplow#62)
  • Loading branch information
AALEKH authored and fblundun committed Mar 17, 2015
1 parent fa84b47 commit ca58cf9
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 8 deletions.
8 changes: 6 additions & 2 deletions project/Dependencies.scala
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ object Dependencies {
"Snowplow Analytics Maven repo" at "http://maven.snplow.com/releases/",
"Snowplow Analytics Maven snapshot repo" at "http://maven.snplow.com/snapshots/",
// For user-agent-utils
"user-agent-utils repo" at "https://raw.github.com/HaraldWalker/user-agent-utils/mvn-repo/"
"user-agent-utils repo" at "https://raw.github.com/HaraldWalker/user-agent-utils/mvn-repo/",
// For uaParser utils
"user-agent-parser repo" at "https://clojars.org/repo/"
)

object V {
Expand All @@ -38,7 +40,8 @@ object Dependencies {
val useragent = "1.14"
val jacksonDatabind = "2.2.3"
val jsonValidator = "2.2.3"
val mavenArtifact = "3.2.2"
val mavenArtifact = "3.2.2"
val uaParser = "1.3.0"
// Scala
val scalaz7 = "7.0.0"
val snowplowRawEvent = "0.1.0"
Expand Down Expand Up @@ -68,6 +71,7 @@ object Dependencies {
val jacksonDatabind = "com.fasterxml.jackson.core" % "jackson-databind" % V.jacksonDatabind
val jsonValidator = "com.github.fge" % "json-schema-validator" % V.jsonValidator
val mavenArtifact = "org.apache.maven" % "maven-artifact" % V.mavenArtifact
val uaParser = "org.clojars.timewarrior" % "ua-parser" % V.uaParser
// Scala
val scalaz7 = "org.scalaz" %% "scalaz-core" % V.scalaz7
val snowplowRawEvent = "com.snowplowanalytics" % "snowplow-thrift-raw-event" % V.snowplowRawEvent
Expand Down
3 changes: 2 additions & 1 deletion project/SnowplowCommonEnrichBuild.scala
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ object SnowplowCommonEnrichBuild extends Build {
Libraries.useragent,
Libraries.jacksonDatabind,
Libraries.jsonValidator,
Libraries.mavenArtifact,
Libraries.mavenArtifact,
Libraries.uaParser,
// Scala
Libraries.scalaz7,
Libraries.snowplowRawEvent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ object EnrichmentManager {
registry.getUserAgentUtilsEnrichment match {
case Some(uap) => {
Option(event.useragent) match {
case Some(ua) =>
case Some(ua) =>
val ca = uap.extractClientAttributes(ua)
ca.flatMap(c => {
event.br_name = c.browserName
Expand All @@ -278,6 +278,19 @@ object EnrichmentManager {
}
}

val uaParser = {
registry.getUaParserEnrichment match {
case Some(uap) => {
Option(event.useragent) match {
case Some(ua) =>
var uaJsonPlaceholder = uap.extractUserAgent(ua)
case None => unitSuccess // No fields updated
}
}
case None => unitSuccess
}
}

// Potentially set the referrer details and URL components
val refererUri = CU.stringToUri(event.page_referrer)
for (uri <- refererUri; u <- uri) {
Expand Down
21 changes: 18 additions & 3 deletions ...n/scala/com.snowplowanalytics.snowplow.enrich/common/enrichments/EnrichmentRegistry.scala
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,16 @@ import registry.{
IpLookupsEnrichment,
RefererParserEnrichment,
CampaignAttributionEnrichment,
UserAgentUtilsEnrichment
UserAgentUtilsEnrichment,
UaParserEnrichment
}

// UserAgentUtilsEnrichmentConfig
import registry.UserAgentUtilsEnrichmentConfig

// UaParserEnrichmentConfig
import registry.UaParserEnrichmentConfig

import utils.ScalazJson4sUtils


Expand Down Expand Up @@ -133,7 +137,9 @@ object EnrichmentRegistry {
CampaignAttributionEnrichment.parse(enrichmentConfig, schemaKey).map((nm, _).some)
} else if (nm == "user_agent_utils_config") {
UserAgentUtilsEnrichmentConfig.parse(enrichmentConfig, schemaKey).map((nm, _).some)
} else {
} else if (nm == "ua_parser_config") {
UaParserEnrichmentConfig.parse(enrichmentConfig, schemaKey).map((nm, _).some)
}else {
None.success // Enrichment is not recognized yet
}
})
Expand Down Expand Up @@ -200,7 +206,16 @@ case class EnrichmentRegistry(private val configs: EnrichmentMap) {
* @return Option boxing the UserAgentUtilsEnrichment instance
*/
def getUserAgentUtilsEnrichment: Option[UserAgentUtilsEnrichment.type] =
getEnrichment[UserAgentUtilsEnrichment.type]("user_agent_utils")
getEnrichment[UserAgentUtilsEnrichment.type]("user_agent_utils_config")

/**
* Returns an Option boxing the UaParserEnrichment
* config value if present, or None if not
*
* @return Option boxing the UaParserEnrichment instance
*/
def getUaParserEnrichment: Option[UaParserEnrichment.type] =
getEnrichment[UaParserEnrichment.type]("ua_parser_config")

/**
* Returns an Option boxing an Enrichment
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*Copyright (c) 2012-2015 Snowplow Analytics Ltd. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/
package com.snowplowanalytics
package snowplow
package enrich
package common
package enrichments
package registry

// Maven Artifact
import org.apache.maven.artifact.versioning.DefaultArtifactVersion

// Scalaz
import scalaz._
import Scalaz._

// ua-parser
import ua_parser.Parser
import ua_parser.Client
import ua_parser.Client

// json4s
import org.json4s._
import org.json4s.JValue
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods._

// Iglu
import iglu.client.SchemaKey
import iglu.client.validation.ProcessingMessageMethods._
import utils.ScalazJson4sUtils

/**
* Companion object. Lets us create a UaParserEnrichment
* from a JValue.
*/
object UaParserEnrichmentConfig extends ParseableEnrichment {

val supportedSchemaKey = SchemaKey("com.snowplowanalytics.snowplow", "ua_parser_config", "jsonschema", "1-0-0")

def parse(config: JValue, schemaKey: SchemaKey): ValidatedNelMessage[UaParserEnrichment.type] =
isParseable(config, schemaKey).map(_ => UaParserEnrichment)
}

/**
* Config for an ua_parser_config enrichment
*
* Uses uap-java library to parse client attributes
*/
case object UaParserEnrichment extends Enrichment {

val version = new DefaultArtifactVersion("0.1.0")

/*
* Check's for null for Option Version variable
*/
def prependDot (versionElement: String) :String = {
if (versionElement != null) {
"." + versionElement
} else {
""
}
}

/*
* Prepends space before the versionElement
*/
def prependSpace (versionElement: String) :String = {
if (versionElement != null) {
" " + versionElement
} else {
""
}
}

/*
* Check's for null value in versionElement for family parameter
*/
def checkNull (versionElement:String) :String = {
if(versionElement == null) {
""
} else {
versionElement
}
}
/**
* Extracts the client attributes
* from a useragent string, using
* UserAgentEnrichment.
*
* @param useragent The useragent
* String to extract from.
* Should be encoded (i.e.
* not previously decoded).
* @return the json or
* the message of the
* exception, boxed in a
* Scalaz Validation
*/
def extractUserAgent(useragent: String): Validation[String, JsonAST.JObject] = {

val uaParser = new Parser()

val c = try {
uaParser.parse(useragent)
} catch {
case e => return "Exception parsing useragent [%s]: [%s]".format(useragent, e.getMessage).fail
}
// To display useragent version
val useragentVersion = checkNull(c.userAgent.family) + prependSpace(c.userAgent.major) + prependDot(c.userAgent.minor) + prependDot(c.userAgent.patch)

// To display operating system version
val osVersion = checkNull(c.os.family) + prependSpace(c.os.major) + prependDot(c.os.minor) + prependDot(c.os.patch) + prependDot(c.os.patchMinor)

val json =
( ("schema" -> "iglu:com.snowplowanalytics.snowplow/ua_parser_context/jsonschema/1-0-0") ~
("data" ->
("useragentFamily" -> c.userAgent.family) ~
("useragentMajor" -> c.userAgent.major) ~
("useragentMinor" -> c.userAgent.minor) ~
("useragentPatch" -> c.userAgent.patch) ~
("useragentVersion" -> useragentVersion) ~
("osFamily" -> c.os.family) ~
("osMajor" -> c.os.major) ~
("osMinor" -> c.os.minor) ~
("osPatch" -> c.os.patch) ~
("osPatchMinor" -> c.os.patchMinor) ~
("osVersion" -> osVersion) ~
("deviceFamily" -> c.device.family)
)
)

json.success
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*Copyright <Notice>
/*Copyright (c) 2012-2015 Snowplow Analytics Ltd. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
Expand Down
17 changes: 17 additions & 0 deletions ...snowplowanalytics.snowplow.enrich.common/enrichments/registry/EnrichmentConfigsSpec.scala
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,21 @@ class EnrichmentConfigsSpec extends Specification with ValidationMatchers {
}
}

"Parsing a valid ua_parser_config enrichment JSON" should {
"successfully construct a UaParserEnrichment case object" in {

val uaParserEnrichmentJson = parse("""{
"enabled": true,
"parameters": {
}
}""")

val schemaKey = SchemaKey("com.snowplowanalytics.snowplow", "ua_parser_config", "jsonschema", "1-0-0")

val result = UaParserEnrichmentConfig.parse(uaParserEnrichmentJson, schemaKey)
result must beSuccessful(UaParserEnrichment)

}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**Copyright (c) 2012-2015 Snowplow Analytics Ltd. All rights reserved.
*
* This program is licensed to you under the Apache License Version 2.0,
* and you may not use this file except in compliance with the Apache License Version 2.0.
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the Apache License Version 2.0 is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/

package com.snowplowanalytics.snowplow.enrich.common
package enrichments
package registry

// Specs2
import org.specs2.Specification
import org.specs2.matcher.DataTables
import org.specs2.scalaz._

// Scalaz
import scalaz._
import Scalaz._

// Json4s
import org.json4s._
import org.json4s.JValue
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods._

class UaParserEnrichmentSpec extends org.specs2.mutable.Specification with ValidationMatchers with DataTables {
import UaParserEnrichment._
val jsonTest = """{"schema":"iglu:com.snowplowanalytics.snowplow/ua_parser_context/jsonschema/1-0-0","data":{"useragentFamily":"Mobile Safari","useragentMajor":"5","useragentMinor":"1","useragentPatch":null,"useragentVersion":"Mobile Safari 5.1","osFamily":"iOS","osMajor":"5","osMinor":"1","osPatch":"1","osPatchMinor":null,"osVersion":"iOS 5.1.1","deviceFamily":"iPhone"}}"""
val jsonTestNew = """{"schema":"iglu:com.snowplowanalytics.snowplow/ua_parser_context/jsonschema/1-0-0","data":{"useragentFamily":"Safari","useragentMajor":"8","useragentMinor":"0","useragentPatch":null,"useragentVersion":"Safari 8.0","osFamily":"Mac OS X","osMajor":"10","osMinor":"10","osPatch":null,"osPatchMinor":null,"osVersion":"Mac OS X 10.10","deviceFamily":"Other"}}"""

"useragent parser" should {
"parse useragent" in {
"Input UserAgent" | "Parsed UserAgent" |
"Mozilla/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3" !! jsonTest |
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25" !! jsonTestNew |> {
(input, expected) => {
UaParserEnrichment.extractUserAgent(input) must beSuccessful.like { case a => compact(render(a)) must_== compact(render(parse(expected))) }
}
}
}
}
}

0 comments on commit ca58cf9

Please sign in to comment.