BehaviorSummary
/**
* @file BehaviorSummaryReport
* @reportoverview An executive summary report that shows the behavior, key and level events over a time range and
* the top behavior rules by hits.
*/
/**
* Main method. This method breaks the time range into 1 day intervals and gets the behavior events for each day.
* The overall table is then broken down into smaller tables based on the behavior, key and level.
*
* @param {string || int} from - The start of the time range. Default is 1 day ago from the past hour
* @param {string || int} to - The end of the time range. Default is the past minute
*
* @returns {object} - Returns an object containing all the tables/metric/alert obtained from the queries
*/
function main({from="-1d@m", to="@m"}) {
let rangeFrom = new Time(from)
let rangeTo = new Time(to)
validateTimeRange(rangeFrom, rangeTo)
setEnv("from", from)
setEnv("to", to)
let events = new Table()
// breaks the time down into 1 day intervals and gets the activity timeline for each day
let interval = "1d"
for (let t = rangeFrom; t.Before(rangeTo); t = t.Add(interval)) {
let from = t
let to = t.Add(interval).After(rangeTo) ? rangeTo : t.Add(interval)
let table = Fluency_SummarySearch("riskScore: [4000 TO *]", from.UnixMilli(), to.UnixMilli(), (obj) => {
let {dayIndex, behaviors, riskScore, key, keyType, summaryList } = obj
let behaviorRules = []
let behaviorRulesCount = []
// parses each behavior rule hit and count as new columns
for (let i = 0; i < len(summaryList); i++) {
let summary = summaryList[i]
// only add events with a risk score
if (summary.riskScore > 0) {
behaviorRules = append(behaviorRules, summary.behaviorRule)
behaviorRulesCount = append(behaviorRulesCount, (summary.count))
}
}
return {dayIndex, riskScore, key, keyType, behaviors, behaviorRules, behaviorRulesCount}
})
events.Append(table)
}
// creates a new level column based on the risk score
events.NewColumnLambda("level", "", ({riskScore}) => {
return riskScore >= 6000 ? (riskScore < 8000 ? "serious" : "critical") : "high"
})
// gets the list of behavior values
let behaviors = []
try {
let behaviorValues = events.GetColumnValues("behaviors")
for (let i = 0; i < len(behaviorValues); i++) {
for (let j = 0; j < len(behaviorValues[i]); j++) {
let value = behaviorValues[i][j]
if (!behaviors.Some((_, e) => e.behavior == value)) {
behaviors = append(behaviors, {behavior: value, count: 1})
} else {
let behavior = behaviors.Find((_, e) => e.behavior == value)
behavior.count++
}
}
}
behaviors = jsonTable(behaviors)
} catch (e) {
// return empty table
behaviors = new Table()
}
// aggregate the table by key
let keys = events.Aggregate(({keyType}) => {
return {
groupBy: {key: keyType},
columns: {
count: {count: true}
}
}
})
// aggregates the table by level and day index
let levels = events.Clone()
let dayAverage = events.Clone()
// aggregates the table by level and if the time range is more than 2 months, it will aggregate by month instead of day
if (rangeTo.After(rangeFrom.Add("60d"))) {
levels = levels.Aggregate(({level, dayIndex}) => {
let dayIndex = subString(dayIndex, 0, 6) + "01"
return {
groupBy: {level, dayIndex},
columns: {
count: {count: true}
}
}
})
// gets the average level for each month
dayAverage = dayAverage.Aggregate(({dayIndex, riskScore}) => {
let dayIndex = subString(dayIndex, 0, 6) + "01"
return {
groupBy: {dayIndex},
columns: {
avg: {average: riskScore}
}
}
})
} else {
levels = levels.Aggregate(({level, dayIndex}) => {
return {
groupBy: {level, dayIndex},
columns: {
count: {count: true}
}
}
})
// gets the average level for each day
dayAverage = dayAverage.Aggregate(({dayIndex, riskScore}) => {
return {
groupBy: {dayIndex},
columns: {
avg: {average: riskScore}
}
}
})
}
// sorts the tables by day index
levels = levels.Sort(0, "+dayIndex")
dayAverage = dayAverage.Sort(0, "+dayIndex")
// gets the top behavior rules by hits
let topBehaviorRules = []
try {
let hits = events.GetColumnValues("behaviorRules")
let hitsCount = events.GetColumnValues("behaviorRulesCount")
for (let i = 0; i < len(hits); i++) {
for (let j = 0; j < len(hits[i]); j++) {
let hit = hits[i][j]
let hitCount = hitsCount[i][j]
if (!topBehaviorRules.Some((_, e) => e.behaviorRule == hit)) {
topBehaviorRules = append(topBehaviorRules, {behaviorRule: hit, count: hitCount})
} else {
let behaviorRuleHit = topBehaviorRules.Find((_, e) => e.behaviorRule == hit)
behaviorRuleHit.count += hitCount
}
}
}
topBehaviorRules = jsonTable(topBehaviorRules).Sort(10, "-count")
} catch (e) {
// return empty table
topBehaviorRules = new Table()
}
return {
behaviors,
keys,
levels,
topBehaviorRules,
dayAverage
}
}
/**
* Thie method is a helper method to validate the time range passed by the user.
*
* @param {Time} from - The start of the time range
* @param {Time} to - The end of the time range
*
* @returns {boolean} - Returns true if the time range is valid
*/
function validateTimeRange(from, to) {
// checks to see if the start of the time range is after the end of the time range
if (from.After(to)) {
throw new Error("rangeFrom must be less than rangeTo", "RangeError")
}
return true
}
Updated 8 months ago