Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies {
implementation 'com.google.android.exoplayer:exoplayer:2.18.5'
implementation 'com.facebook.fresco:fresco:3.0.0'
implementation 'com.github.bumptech.glide:glide:4.15.1'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.15.1'
implementation 'com.squareup.picasso:picasso:2.8'

implementation platform('com.google.firebase:firebase-bom:31.5.0')
Expand All @@ -68,4 +69,10 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation("io.ktor:ktor-client-content-negotiation:2.2.4")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.2.4")
implementation("io.ktor:ktor-client-cio:2.2.4")
implementation("com.google.code.gson:gson:2.10.1")
implementation("com.github.BetsonWick:NetworkMonitor:1.1.1")

}
2 changes: 2 additions & 0 deletions app/src/main/java/ru/ok/android/itmohack2023/GlideActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import ru.ok.android.itmohack2023.logcat.LogcatHelper.Companion.createGlide

class GlideActivity : AppCompatActivity() {
private lateinit var cat1: ImageView
Expand All @@ -13,6 +14,7 @@ class GlideActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_glide)
createGlide(this)

cat1 = findViewById(R.id.cat_photo_1)
cat2 = findViewById(R.id.cat_photo_2)
Expand Down
22 changes: 22 additions & 0 deletions app/src/main/java/ru/ok/android/itmohack2023/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
package ru.ok.android.itmohack2023

import android.app.ActivityManager
import android.app.usage.NetworkStatsManager
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import ru.ok.android.itmohack2023.logcat.LogcatHelper
import ru.itmo.networkmonitor.NetworkMonitorTask


class MainActivity : AppCompatActivity() {
@RequiresApi(Build.VERSION_CODES.M)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val logcatHelper = LogcatHelper(60 * 1000, this)
CoroutineScope(Dispatchers.Default).launch {
logcatHelper.publish()
}
NetworkMonitorTask(
getSystemService(NETWORK_STATS_SERVICE) as NetworkStatsManager, getSystemService(
Context.ACTIVITY_SERVICE
) as ActivityManager,
listOf("ru.ok")
).start()
findViewById<View>(R.id.url_connection).setOnClickListener {
startActivity(Intent(this, UrlConnectionActivity::class.java))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatActivity
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONArray
import ru.ok.android.itmohack2023.logcat.LogcatHelper
import java.io.IOException

class OkHttpActivity : AppCompatActivity() {
Expand Down Expand Up @@ -43,6 +44,6 @@ class OkHttpActivity : AppCompatActivity() {
val request: Request = Request.Builder()
.url(url)
.build()
OkHttpClient().newCall(request).execute().use { response -> return response.body?.string() }
LogcatHelper.okHttpClient.newCall(request).execute().use { response -> return response.body?.string() }
}
}
111 changes: 111 additions & 0 deletions app/src/main/java/ru/ok/android/itmohack2023/logcat/LogcatHelper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package ru.ok.android.itmohack2023.logcat

import android.content.Context
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.bumptech.glide.Glide
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
import com.bumptech.glide.load.model.GlideUrl
import com.google.gson.Gson
import com.squareup.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.client.utils.EmptyContent.contentType
import io.ktor.http.ContentType
import io.ktor.http.contentType
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.util.concurrent.TimeUnit


class LogcatHelper(private val timeout: Long, mainContext: Context) {
companion object {
private const val LOG_TAG = "LogcatHandler"
val okHttpClient: OkHttpClient = OkHttpClient().newBuilder()
.addInterceptor(HttpLoggingInterceptor {
Log.d(LOG_TAG, it)
}
.setLevel(HttpLoggingInterceptor.Level.BODY))
.connectTimeout(5, TimeUnit.SECONDS)
.build()

fun createGlide(context: Context) {
Glide.get(context).registry
.replace(
GlideUrl::class.java,
InputStream::class.java, OkHttpUrlLoader.Factory(okHttpClient)
)
}
var processed = 0
}

val parser = LogcatParser()

init {
Picasso.setSingletonInstance(
Picasso.Builder(mainContext)
.downloader(OkHttp3Downloader(okHttpClient))
.build()
)

}

@RequiresApi(Build.VERSION_CODES.N)
suspend fun publish() {
while (true) {
val process = withContext(Dispatchers.IO) {
Runtime.getRuntime().exec("logcat -d")
}
val lines = BufferedReader(InputStreamReader(process.inputStream))
.readLines()
.filter { it.contains(LOG_TAG) }
val logs = lines
.drop(processed)
.map { parser.parse(it) }
.filterNotNull()
.filter { it.sender == LOG_TAG }
.groupBy { it.identification }
processed += lines.size

val finalLogs = mutableListOf<LogcatRequest>()

for (log in logs) {
val request = parser.processAnswer(log.value)
if (request != null) {
finalLogs.add(request)
}
}
val client = HttpClient(CIO) {
expectSuccess = true
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
}
runBlocking {

client.post("http://10.0.2.2:8080/addEvent") {
contentType(ContentType.Application.Json)
setBody(Gson().toJson(finalLogs))
}
}
withContext(Dispatchers.IO) {
Thread.sleep(timeout)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ru.ok.android.itmohack2023.logcat

import java.time.LocalDateTime

data class LogcatInfo(var time: LocalDateTime, var identification: String, var sender: String, var logBody: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package ru.ok.android.itmohack2023.logcat

import java.lang.RuntimeException
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

class LogcatParser {
private val timeRegex = Regex("\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3}")
private val identificationRegex = Regex("\\d+ \\d+")
private val messRegex = Regex("D|I|E|A|W")
private val senderRegex = Regex("\\w+")
private val typeRegex = Regex("GET|POST|DELETE")

private fun process(match: MatchResult?): String {
if (match == null) {
throw RuntimeException("Log hasn't matched")
}
return match.value
}

fun parse(input: String): LogcatInfo? {
try {
var log = input
val time = "2023-" + process(timeRegex.find(log))
log = log.replaceFirst(timeRegex, "")

val identification = process(identificationRegex.find(log))
log = log.replaceFirst(identificationRegex, "")

log = log.replaceFirst(messRegex, "").trim()

val sender = process(senderRegex.find(log))
log = log.replaceFirst(senderRegex, "")
val logBody = log.replaceFirst(":", "").trim()

return LogcatInfo(
time = LocalDateTime.parse(
time,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
),
identification = identification,
sender = sender,
logBody = logBody
)
} catch (e: Exception) {
return null
}
}

fun processAnswer(logs: List<LogcatInfo>) : LogcatRequest? {
try {
val start = logs.filter { it.logBody.startsWith("-->") }[0]
val response = logs.filter { it.logBody.startsWith("<--") }[0]
val finish = logs.filter { it.logBody.startsWith("<-- END HTTP") }[0]
val type = process(typeRegex.find(start.logBody))
val bytes = process(Regex("\\d+").find(finish.logBody)).toLong()
return LogcatRequest(startTimestamp = start.time,
finishTimestamp = finish.time,
request = start.logBody.replaceFirst("--> ", ""),
response = response.logBody.replaceFirst("<-- ", ""),
bytesCount = bytes,
type = type
)
} catch (e: Exception) {
return null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ru.ok.android.itmohack2023.logcat

import java.time.LocalDateTime

data class LogcatRequest(
var request: String,
var response: String,
var type: String,
var startTimestamp: LocalDateTime,
var finishTimestamp: LocalDateTime,
var bytesCount: Long
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@ import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import ru.ok.android.itmohack2023.logcat.LogcatHelper.Companion.okHttpClient
import java.util.concurrent.TimeUnit

object RetrofitProvider {

val retrofit: Retrofit by lazy {
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.connectTimeout(5, TimeUnit.SECONDS)
.build()
val gson = GsonBuilder()
.setPrettyPrinting()
.create()
Expand Down
9 changes: 4 additions & 5 deletions local.properties
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file should *NOT* be checked into Version Control Systems,
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=/Users/kirill.popov/Library/Android/sdk
#Sun Apr 16 15:26:28 MSK 2023
sdk.dir=/Users/mk17ru/Library/Android/sdk

1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
rootProject.name = "ItmoHack2023"
Expand Down