package com.loginfail
import java.util
import org.apache.flink.api.common.state.{ListState, ListStateDescriptor, ValueState, ValueStateDescriptor}
import org.apache.flink.shaded.netty4.io.netty.handler.codec.http2.Http2Exception.StreamException
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.KeyedProcessFunction
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.util.Collector
import scala.collection.mutable.ListBuffer
object LonginFail {
case class LonginEvent(userId:Long,ip:String,eventType:String,timestamp:Long)
//输出报警信息样例类
case class LonginFailWarning(userId:Long,firstFailTime:Long,lastFailTime:Long,waringMsg:String)
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
val inputStream: DataStream[String] = env.readTextFile(“F:\UserBehaviorAnalysis\LongInFail\src\main\resources\LoginLog.csv”)
val loginStream: DataStream[LonginEvent] = inputStream.map(
data => {
val arr = data.split(",")
LonginEvent(arr(0).toLong, arr(1), arr(2), arr(3).toLong)
}
).assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractorLonginEvent {
override def extractTimestamp(element: LonginEvent): Long = element.timestamp*1000L
})
//继续判断监测 如果2s内连续登录失败 输出报警信息
//1.使用procss 的ontimer方法
val resultStream: DataStream[LonginFailWarning] = loginStream
.keyBy(_.userId)
.process(new LoginFailWarningResult(2))
resultStream.print()
env.execute()
}
class LoginFailWarningResult(failTimes: Int) extends KeyedProcessFunction[Long,LonginEvent,LonginFailWarning]{
//定义状态 保存当前的登录失败
lazy val loginFailStateList: ListState[LonginEvent] = getRuntimeContext.getListState(new ListStateDescriptorLonginEvent)
lazy val timeTsState: ValueState[Long] = getRuntimeContext.getState(new ValueStateDescriptorLong)
override def processElement(value: LonginEvent, ctx: KeyedProcessFunction[Long, LonginEvent, LonginFailWarning]#Context, out: Collector[LonginFailWarning]): Unit = {
if(value.eventType == “fail”){
loginFailStateList.add(value)
if(timeTsState.value()==0){
val ts: Long = value.timestamp*1000+2000L
ctx.timerService().registerEventTimeTimer(ts) //定义2s后触发的定时器
timeTsState.update(ts)
}
}else{
//如果成功 直接清空状态和定时器 重新开始
ctx.timerService().deleteEventTimeTimer(timeTsState.value())
loginFailStateList.clear()
timeTsState.clear()
}
}
override def onTimer(timestamp: Long, ctx: KeyedProcessFunction[Long, LonginEvent, LonginFailWarning]#OnTimerContext, out: Collector[LonginFailWarning]): Unit = {
val buffer:ListBuffer[LonginEvent] = ListBufferLonginEvent
val iter: util.Iterator[LonginEvent] = loginFailStateList.get().iterator()
while (iter.hasNext){
buffer+=iter.next()
}
if(buffer.size>= failTimes){
out.collect(LonginFailWarning(buffer.head.userId,buffer.head.timestamp,buffer.last.timestamp,“连续登录失败”+buffer.size
))
}
loginFailStateList.clear()
timeTsState.clear()
}
}
}