Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(logger): added type & duration filters for logs #311

Closed
wants to merge 3 commits into from
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.pluto.plugins.logger

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import com.pluto.plugins.logger.internal.LogTimeStamp
import com.pluto.plugins.logger.internal.LogType
import com.pluto.plugins.logger.internal.Session
import com.pluto.utilities.selector.SelectorOption

internal class FilterViewModel(application: Application) : AndroidViewModel(application) {
val selectedFiltersList: LiveData<List<LogType>>
get() = _selectedFiltersList
private val _selectedFiltersList = MutableLiveData<List<LogType>>()

val selectedTimeStamp: LiveData<LogTimeStamp>
get() = _selectedTimeStamp
private val _selectedTimeStamp = MutableLiveData<LogTimeStamp>()

val searchTextLogger: LiveData<String>
get() = _searchTextLogger
private val _searchTextLogger = MutableLiveData<String>()

private val preferences = Preferences(application)
private val logTypes = listOf(
LogType("debug"),
LogType("verbose"),
LogType("error"),
LogType("info"),
LogType("event")
)

private val timeStamps = listOf(
LogTimeStamp(1),
LogTimeStamp(5),
LogTimeStamp(10),
LogTimeStamp(Integer.MIN_VALUE, true)
)

val isTriggerSearch: LiveData<Boolean>
get() = _isTriggerSearch
private val _isTriggerSearch = MediatorLiveData<Boolean>()
val isFilterApplied: LiveData<Boolean>
get() = _isFilterApplied
private val _isFilterApplied = MediatorLiveData<Boolean>()

val isFilterVisible: LiveData<Boolean>
get() = _isFilterVisible
private val _isFilterVisible = MediatorLiveData<Boolean>()

init {

_isTriggerSearch.addSource(_selectedFiltersList) { _isTriggerSearch.postValue(true) }
_isTriggerSearch.addSource(_searchTextLogger) { _isTriggerSearch.postValue(true) }
_isTriggerSearch.addSource(_selectedTimeStamp) { _isTriggerSearch.postValue(true) }
_searchTextLogger.postValue(Session.loggerSearchText)
_selectedFiltersList.postValue(preferences.selectedFilterLogType)
_selectedTimeStamp.postValue(preferences.selectedFilterTime)
_isFilterApplied.addSource(_selectedFiltersList) {
if (it.isNotEmpty() || getSelectedTimeStamp().timeStamp != 0) {
_isFilterApplied.postValue(true)
} else {
_isFilterApplied.postValue(false)
}
}
_isFilterApplied.addSource(_selectedTimeStamp) {
if (it.timeStamp != 0 || getSelectedFilters().isNotEmpty()) {
_isFilterApplied.postValue(true)
} else {
_isFilterApplied.postValue(false)
}
}
_isFilterVisible.postValue(false)
}

fun getLogTypes(): List<SelectorOption> {
return logTypes
}

fun getTimeStamps(): List<SelectorOption> {
return timeStamps
}

fun getSelectedFilters(): List<LogType> {
return selectedFiltersList.value ?: emptyList()
}

fun getSelectedTimeStamp(): LogTimeStamp {
return selectedTimeStamp.value ?: LogTimeStamp(0, false)
}

fun updateSearchText(searchText: String) {
_searchTextLogger.postValue(searchText)
Session.loggerSearchText = searchText
}

fun setSelectedFiltersLogType(logTypeList: ArrayList<LogType>) {
_selectedFiltersList.postValue(logTypeList)
preferences.selectedFilterLogType = logTypeList
}
fun setSelectedFilterTimeStamp(logTimeStamp: LogTimeStamp) {
_selectedTimeStamp.postValue(logTimeStamp)
preferences.selectedFilterTime = logTimeStamp
}
fun getSearchText(): String {
return searchTextLogger.value ?: ""
}

fun toggleFilterViewVisibility() {
_isFilterVisible.postValue(_isFilterVisible.value?.not())
}
fun clearFilters() {
preferences.clearFilters()
_selectedFiltersList.postValue(emptyList())
_selectedTimeStamp.postValue(LogTimeStamp(0, false))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class PlutoLoggerPlugin() : Plugin(ID) {
@Deprecated("Use the default constructor PlutoLoggerPlugin() instead.")
constructor(identifier: String) : this()

private val settingsPreferences by lazy { Preferences(application) }

override fun getConfig(): PluginConfiguration = PluginConfiguration(
name = context.getString(R.string.pluto_logger___plugin_name),
icon = R.drawable.pluto_logger___ic_logger_icon,
Expand All @@ -35,6 +37,7 @@ class PlutoLoggerPlugin() : Plugin(ID) {

override fun onPluginDataCleared() {
LogDBHandler.flush()
settingsPreferences.clearFilters()
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.pluto.plugins.logger

import android.content.Context
import com.pluto.plugins.logger.internal.LogTimeStamp
import com.pluto.plugins.logger.internal.LogType
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types

internal class Preferences(context: Context) {

private val settingsPrefs by lazy { context.preferences("_pluto_log_filter_settings") }
private val moshi: Moshi = Moshi.Builder().build()
private val moshiAdapter: JsonAdapter<List<String>> =
moshi.adapter(Types.newParameterizedType(List::class.java, String::class.java))

private var timeStampAdapter: JsonAdapter<LogTimeStamp> =
moshi.adapter(LogTimeStamp::class.java)

internal var selectedFilterLogType: List<LogType>
get() = settingsPrefs.getString(SELECTED_FILTER_LOG_TYPE, null)?.let {
moshiAdapter.fromJson(it)?.map { type -> LogType(type) }
} ?: run { emptyList() }
set(value) = settingsPrefs.edit()
.putString(SELECTED_FILTER_LOG_TYPE, moshiAdapter.toJson(value.map { it.type })).apply()

internal var selectedFilterTime: LogTimeStamp
get() = settingsPrefs.getString(SELECTED_FILTER_TIMESTAMP, null)?.let {
timeStampAdapter.fromJson(it)
} ?: run { LogTimeStamp(0, false) }
set(value) = settingsPrefs.edit()
.putString(SELECTED_FILTER_TIMESTAMP, timeStampAdapter.toJson(value)).apply()

companion object {
private const val SELECTED_FILTER_LOG_TYPE = "selected_filter_logtype"
private const val SELECTED_FILTER_TIMESTAMP = "selected_filter_timestamp"
}

fun clearFilters() {
settingsPrefs.edit().clear().apply()
}
}

private fun Context.preferences(name: String, mode: Int = Context.MODE_PRIVATE) =
getSharedPreferences(name, mode)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.annotation.DrawableRes
import androidx.annotation.Keep
import com.pluto.plugins.logger.R
import com.pluto.utilities.list.ListItem
import com.pluto.utilities.selector.SelectorOption
import com.squareup.moshi.JsonClass

@Keep
Expand All @@ -20,7 +21,11 @@ internal open class Level(
object Warning : Level("warning")
object WTF : Level("wtf")
object Error : Level("error", R.color.pluto___red_05, R.color.pluto___red_80)
object Event : Level(label = "event", iconRes = R.drawable.pluto_logger___ic_analytics, textColor = R.color.pluto___blue)
object Event : Level(
label = "event",
iconRes = R.drawable.pluto_logger___ic_analytics,
textColor = R.color.pluto___blue
)
}

@Keep
Expand All @@ -47,3 +52,30 @@ internal data class StackTrace(
val fileName: String,
val lineNumber: Int,
)

@Keep
@JsonClass(generateAdapter = true)
internal data class LogType(
val type: String
) : SelectorOption() {
override fun displayText(): CharSequence {
return type
}
}

@Keep
@JsonClass(generateAdapter = true)
internal data class LogTimeStamp(
val timeStamp: Int = 0,
val isSessionFilter: Boolean = false
) : SelectorOption() {
override fun displayText(): CharSequence {
if (isSessionFilter) {
return "Current session only"
}
if (timeStamp == 1) {
return "< $timeStamp minute"
}
return "< $timeStamp minutes"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.pluto.plugins.logger.internal.persistence.LogDBHandler
import com.pluto.plugins.logger.internal.persistence.LogEntity
import com.pluto.utilities.extensions.asFormattedDate
import com.pluto.utilities.list.ListItem
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

Expand All @@ -27,13 +28,36 @@ internal class LogsViewModel(application: Application) : AndroidViewModel(applic
get() = _serializedLogs
private val _serializedLogs = MutableLiveData<String>()

fun fetch(search: String = "") {
fun searchAndFilter(
search: String = "",
logType: List<LogType> = emptyList(),
logTimeStamp: LogTimeStamp = LogTimeStamp(0, false)
) {
viewModelScope.launch(Dispatchers.IO) {
if (rawLogs == null) {
rawLogs = LogDBHandler.fetchAll()
}
val currentSessionLogs = (rawLogs ?: arrayListOf()).filter { it.sessionId == Session.id && it.data.isValidSearch(search) }.map { it.data }
val previousSessionLogs = (rawLogs ?: arrayListOf()).filter { it.sessionId != Session.id && it.data.isValidSearch(search) }.map { it.data }
val currentSessionLogs =
(rawLogs ?: arrayListOf())
.asSequence()
.filter { it.sessionId == Session.id }
.filter { pastTimeFilter(it.timestamp, logTimeStamp) }
.filter { logType.map { type -> type.type }.contains(it.data.tag) }
.filter { it.data.isValidSearch(search) }
.map { it.data }
.toList()

val previousSessionLogs = if (!logTimeStamp.isSessionFilter) {
(rawLogs ?: arrayListOf())
.asSequence()
.filter { it.sessionId != Session.id }
.filter { it.data.isValidSearch(search) }
.filter { pastTimeFilter(it.timestamp, logTimeStamp) }
.map { it.data }
.toList()
} else {
emptyList()
}

val list = arrayListOf<ListItem>()
list.addAll(currentSessionLogs)
Expand All @@ -45,6 +69,13 @@ internal class LogsViewModel(application: Application) : AndroidViewModel(applic
}
}

private fun pastTimeFilter(logTime: Long, log: LogTimeStamp): Boolean {
if (log.timeStamp == 0 || log.isSessionFilter) {
return true
}
return logTime >= System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(log.timeStamp.toLong())
}

fun deleteAll() {
viewModelScope.launch(Dispatchers.IO) {
LogDBHandler.flush()
Expand Down Expand Up @@ -93,5 +124,8 @@ internal class LogsViewModel(application: Application) : AndroidViewModel(applic
}
}

private fun LogData.isValidSearch(search: String): Boolean =
search.isEmpty() || tag.contains(search, true) || message.contains(search, true) || stackTrace.fileName.contains(search, true)
private fun LogData.isValidSearch(search: String): Boolean {
return search.isEmpty() ||
message.contains(search, true) ||
stackTrace.fileName.contains(search, true)
}
Loading
Loading