Skip to content

Commit

Permalink
Bigquery samtalereferat metrikker (#835)
Browse files Browse the repository at this point in the history
Lagre følgende metrikker i BigQuery

Oppsummering av fordeling av "aktive" samtalereferat på publisert / ikke publisert i big-query tabellen SAMTALEREFERAT_FORDELING
Lagre events av typene "Samtalereferat / Mote - opprettet" og "Samtalereferat / Mote - delt med bruker" i big-query tabellen SAMTALEREFERAT_EVENTS

---------

Co-authored-by: johannetronstad <[email protected]>
  • Loading branch information
tu55eladd and johatr authored Oct 30, 2024
1 parent 9b1f987 commit aea2d72
Show file tree
Hide file tree
Showing 15 changed files with 193 additions and 5 deletions.
4 changes: 4 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ dependencies {
// Hvis det ønskes swagger doc, foreslås å bruke springdoc (springdoc-openapi-starter-webmvc-ui - se no.nav.fo.veilarbdialog.rest.SwaggerConfig for eksempelconfig)
implementation("io.swagger.core.v3:swagger-annotations:2.2.8")

// BigQuery
implementation(platform("com.google.cloud:libraries-bom:26.45.0"))
implementation("com.google.cloud:google-cloud-bigquery")

implementation("io.getunleash:unleash-client-java:8.2.1")

runtimeOnly("org.springframework.boot:spring-boot-devtools")
Expand Down
5 changes: 5 additions & 0 deletions nais/nais-dev-gcp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ spec:
autoInstrumentation:
enabled: true
runtime: java

accessPolicy:
inbound:
rules:
Expand Down Expand Up @@ -107,6 +108,10 @@ spec:
envVarPrefix: DB
users:
- name: datastream
bigQueryDatasets:
- description: Contains big data, supporting big queries, for use in big ideas.
name: aktivitet_metrikker
permission: READWRITE
env:
- name: POAO_TILGANG_SCOPE
value: api://dev-gcp.poao.poao-tilgang/.default
Expand Down
4 changes: 4 additions & 0 deletions nais/nais-prod-gcp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ spec:
envVarPrefix: DB
users:
- name: datastream
bigQueryDatasets:
- description: Funksjonelle metrikker for aktivitetsplan
name: aktivitet_metrikker
permission: READWRITE
env:
- name: POAO_TILGANG_SCOPE
value: api://prod-gcp.poao.poao-tilgang/.default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import no.nav.veilarbaktivitet.aktivitet.domain.AktivitetTypeData;
import no.nav.veilarbaktivitet.aktivitet.feil.EndringAvFerdigAktivitetException;
import no.nav.veilarbaktivitet.aktivitet.feil.EndringAvHistoriskAktivitetException;
import no.nav.veilarbaktivitet.eventsLogger.BigQueryClient;
import no.nav.veilarbaktivitet.eventsLogger.EventType;
import no.nav.veilarbaktivitet.person.Person;
import no.nav.veilarbaktivitet.person.PersonService;
import org.slf4j.Logger;
Expand All @@ -29,6 +31,7 @@ public class AktivitetAppService {
private final AktivitetService aktivitetService;
private final MetricService metricService;
private final PersonService personService;
private final BigQueryClient bigQueryClient;

private static final Set<AktivitetTypeData> TYPER_SOM_KAN_ENDRES_EKSTERNT = new HashSet<>(Arrays.asList(
AktivitetTypeData.EGENAKTIVITET,
Expand Down Expand Up @@ -111,6 +114,9 @@ public AktivitetData opprettNyAktivitet(AktivitetData aktivitetData) {
}

AktivitetData nyAktivitet = aktivitetService.opprettAktivitet(aktivitetData);
if (nyAktivitet.getAktivitetType() == AktivitetTypeData.SAMTALEREFERAT || nyAktivitet.getAktivitetType() == AktivitetTypeData.MOTE) {
bigQueryClient.logEvent(nyAktivitet, EventType.SAMTALEREFERAT_OPPRETTET);
}

// dette er gjort på grunn av KVP
return authService.erSystemBruker() ? nyAktivitet.withKontorsperreEnhetId(null) : nyAktivitet;
Expand Down Expand Up @@ -224,12 +230,21 @@ public AktivitetData oppdaterReferat(AktivitetData aktivitet) {
val originalAktivitet = hentAktivitet(aktivitet.getId());
kanEndreAktivitetGuard(originalAktivitet, aktivitet.getVersjon(), aktivitet.getAktorId());

aktivitetService.oppdaterReferat(
var oppdatertAktivtiet = aktivitetService.oppdaterReferat(
originalAktivitet,
aktivitet
);

return hentAktivitet(aktivitet.getId());
if(!originalAktivitet.getMoteData().isReferatPublisert() && oppdatertAktivtiet.getMoteData().isReferatPublisert()) {
bigQueryClient.logEvent(oppdatertAktivtiet, EventType.SAMTALEREFERAT_DELT_MED_BRUKER);
}
var forrigeReferat = originalAktivitet.getMoteData().getReferat();
var nesteReferat = oppdatertAktivtiet.getMoteData().getReferat();
if (forrigeReferat.isEmpty() && !nesteReferat.isEmpty() && oppdatertAktivtiet.getAktivitetType() == AktivitetTypeData.MOTE ) {
bigQueryClient.logEvent(oppdatertAktivtiet, EventType.SAMTALEREFERAT_FIKK_INNHOLD);
}

return oppdatertAktivtiet;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,14 @@ public void oppdaterMoteTidStedOgKanal(AktivitetData originalAktivitet, Aktivite
aktivitetDAO.oppdaterAktivitet(oppdatertAktivitetMedNyFrist);
}

public void oppdaterReferat(
public AktivitetData oppdaterReferat(
AktivitetData originalAktivitet,
AktivitetData aktivitetData
) {
val transaksjon = getReferatTransakjsonType(originalAktivitet, aktivitetData);

val merger = MappingUtils.merge(originalAktivitet, aktivitetData);
aktivitetDAO.oppdaterAktivitet(originalAktivitet
return aktivitetDAO.oppdaterAktivitet(originalAktivitet
.withEndretDato(aktivitetData.getEndretDato())
.withEndretAv(aktivitetData.getEndretAv())
.withEndretAvType(Innsender.NAV) // Bare NAV kan endre referat
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import no.nav.common.auth.context.AuthContextHolderThreadLocal;
import no.nav.common.metrics.Event;
import no.nav.common.metrics.MetricsClient;
import no.nav.veilarbaktivitet.eventsLogger.BigQueryClient;
import no.nav.veilarbaktivitet.eventsLogger.BigQueryClientImplementation;
import no.nav.veilarbaktivitet.unleash.UnleashConfig;
import no.nav.veilarbaktivitet.unleash.strategies.ByEnhetStrategy;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
Expand All @@ -31,6 +33,11 @@ public AuthContextHolder authContextHolder() {
return AuthContextHolderThreadLocal.instance();
}

@Bean
public BigQueryClient bigQueryClient(BigQueryClientImplementation bigQueryClient) {
return bigQueryClient;
}

@Bean
public MetricsClient metricsClient() {
return new MetricsClient() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import no.nav.veilarbaktivitet.aktivitet.mappers.AktivitetDataMapperService
import no.nav.veilarbaktivitet.aktivitetskort.MigreringService
import no.nav.veilarbaktivitet.config.AktivitetResource
import no.nav.veilarbaktivitet.config.OppfolgingsperiodeResource
import no.nav.veilarbaktivitet.eventsLogger.BigQueryClient
import no.nav.veilarbaktivitet.person.UserInContext
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.*
Expand All @@ -29,7 +30,8 @@ class AktivitetsplanController(
private val appService: AktivitetAppService,
private val aktivitetDataMapperService: AktivitetDataMapperService,
private val userInContext: UserInContext,
private val migreringService: MigreringService
private val migreringService: MigreringService,
private val bigQueryClient: BigQueryClient
) {
@Deprecated("Bruk graphql endepunkt")
@GetMapping
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package no.nav.veilarbaktivitet.eventsLogger

import com.google.cloud.bigquery.BigQueryOptions
import com.google.cloud.bigquery.InsertAllRequest
import com.google.cloud.bigquery.TableId
import no.nav.veilarbaktivitet.aktivitet.domain.AktivitetData
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.time.ZoneOffset
import java.time.ZonedDateTime

enum class EventType {
SAMTALEREFERAT_OPPRETTET,
SAMTALEREFERAT_FIKK_INNHOLD,
SAMTALEREFERAT_DELT_MED_BRUKER,
}

data class SamtalereferatPublisertFordeling(
val antallPublisert: Int,
val antallIkkePublisert: Int,
)

interface BigQueryClient {
fun logEvent(aktivitetData: AktivitetData, eventType: EventType)
fun logSamtalereferatFordeling(samtalereferatPublisertFordeling: SamtalereferatPublisertFordeling)
}

@Service
class BigQueryClientImplementation(@Value("\${gcp.projectId}") val projectId: String): BigQueryClient {
val SAMTALEREFERAT_EVENTS = "SAMTALEREFERAT_EVENTS"
val SAMTALEREFERAT_FORDELING = "SAMTALEREFERAT_FORDELING"
val DATASET_NAME = "aktivitet_metrikker"
val moteEventsTable = TableId.of(DATASET_NAME, SAMTALEREFERAT_EVENTS)
val samtalereferatFordelingTable = TableId.of(DATASET_NAME, SAMTALEREFERAT_FORDELING)

fun TableId.insertRequest(row: Map<String, Any>): InsertAllRequest {
return InsertAllRequest.newBuilder(this).addRow(row).build()
}

val bigQuery = BigQueryOptions.newBuilder().setProjectId(projectId).build().service
val log = LoggerFactory.getLogger(BigQueryClient::class.java)

override fun logEvent(aktivitetData: AktivitetData, eventType: EventType) {
val moteRow = mapOf(
"aktivitetId" to aktivitetData.id,
"event" to eventType.name,
"versjon" to aktivitetData.versjon,
"endretDato" to ZonedDateTime.ofInstant(aktivitetData.endretDato.toInstant(), ZoneOffset.systemDefault()).toOffsetDateTime().toString(),
"erPublisert" to aktivitetData.moteData.isReferatPublisert,
"opprettet" to ZonedDateTime.ofInstant(aktivitetData.opprettetDato.toInstant(), ZoneOffset.systemDefault()).toOffsetDateTime().toString(),
"aktivitetsType" to aktivitetData.aktivitetType.name,
"referatLengde" to aktivitetData.moteData.referat.length
)
val moteEvent = moteEventsTable.insertRequest(moteRow)
insertWhileToleratingErrors(moteEvent)
}

override fun logSamtalereferatFordeling(samtalereferatPublisertFordeling: SamtalereferatPublisertFordeling) {
val fordelingRow = mapOf(
"antallPublisert" to samtalereferatPublisertFordeling.antallPublisert,
"antallIkkePublisert" to samtalereferatPublisertFordeling.antallIkkePublisert,
"timestamp" to ZonedDateTime.now().withZoneSameInstant(ZoneOffset.UTC).toOffsetDateTime().toString(),
)
val fordelingInsertRequest = samtalereferatFordelingTable.insertRequest(fordelingRow)
insertWhileToleratingErrors(fordelingInsertRequest)
}

private fun insertWhileToleratingErrors(insertRequest: InsertAllRequest) {
runCatching {
val response = bigQuery.insertAll(insertRequest)
val errors = response.insertErrors
if (errors.isNotEmpty()) {
log.error("Error inserting bigquery rows", errors)
}
}.onFailure {
log.error("BigQuery error", it)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package no.nav.veilarbaktivitet.eventsLogger

import net.javacrumbs.shedlock.spring.annotation.SchedulerLock
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Service

@Service
@EnableScheduling
open class BigQueryMetrikkCron(
val bigQueryClient: BigQueryClient,
val isPublisertDAO: IsPublisertDAO
) {

@Scheduled(cron = "@midnight")
@SchedulerLock(name = "aktiviteter_bigquery_metrikker", lockAtMostFor = "PT2M")
open fun hentPublisertCron() {
val fordeling = isPublisertDAO.hentIsPublisertFordeling()
bigQueryClient.logSamtalereferatFordeling(fordeling)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package no.nav.veilarbaktivitet.eventsLogger

import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.stereotype.Repository

@Repository
open class IsPublisertDAO(
val template: JdbcTemplate
) {
open fun hentIsPublisertFordeling(): SamtalereferatPublisertFordeling {
val sql = """
select count(*) as antall, mote.referat_publisert as erPublisert from mote
join veilarbaktivitet.aktivitet a
on mote.aktivitet_id = a.aktivitet_id and mote.versjon = a.versjon
where mote.referat is not null
and a.til_dato < NOW()
and a.gjeldende = 1 -- Bare siste versjon
and a.historisk_dato is null -- Ikke ta med referat i avsluttede perioder
group by mote.referat_publisert
""".trimIndent()
return template.query(sql) { result, _ ->
val erPublisert = result.getInt("erPublisert")
val antall = result.getInt("antall")
if (erPublisert == 1) SamtalereferatPublisertFordeling(antallPublisert = antall, antallIkkePublisert = 0)
else SamtalereferatPublisertFordeling(antallPublisert = 0, antallIkkePublisert = antall)
}.let { fordelinger ->
SamtalereferatPublisertFordeling(
antallPublisert = fordelinger.sumOf { it.antallPublisert },
antallIkkePublisert = fordelinger.sumOf { it.antallIkkePublisert },
)
}
}
}
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ axsys.url=${AXSYS_URL}
veilarbaktivitet-fss.url=${VEILARBAKTIVITET_FSS_URL}
pdl.url=${PDL_URL}
pdl.scope=${PDL_SCOPE}
gcp.projectId=${GCP_TEAM_PROJECT_ID}

unleash.appName=${NAIS_APP_NAME}
unleash.url=${UNLEASH_SERVER_API_URL}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
create index if not exists mote_publisert_index
on mote (referat_publisert);
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import no.nav.common.token_client.client.TokenXOnBehalfOfTokenClient;
import no.nav.common.utils.Credentials;
import no.nav.veilarbaktivitet.db.DbTestUtils;
import no.nav.veilarbaktivitet.eventsLogger.BigQueryClient;
import no.nav.veilarbaktivitet.mock.MetricsClientMock;
import okhttp3.EventListener;
import org.mockito.Mockito;
Expand All @@ -30,6 +31,11 @@
@EnableConfigurationProperties({EnvironmentProperties.class})
public class ApplicationTestConfig {

@Bean
public BigQueryClient bigQueryClient() {
return mock(BigQueryClient.class);
}

@Bean
public AzureAdMachineToMachineTokenClient tokenClient() {
AzureAdMachineToMachineTokenClient tokenClient = mock(AzureAdMachineToMachineTokenClient.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import no.nav.veilarbaktivitet.aktivitet.domain.BehandlingAktivitetData;
import no.nav.veilarbaktivitet.aktivitet.feil.EndringAvFerdigAktivitetException;
import no.nav.veilarbaktivitet.aktivitet.feil.EndringAvHistoriskAktivitetException;
import no.nav.veilarbaktivitet.eventsLogger.BigQueryClient;
import no.nav.veilarbaktivitet.person.Innsender;
import no.nav.veilarbaktivitet.person.Person;
import no.nav.veilarbaktivitet.person.PersonService;
Expand Down Expand Up @@ -55,6 +56,9 @@ public class AktivitetAppServiceTest {
@InjectMocks
private AktivitetAppService appService;

@Mock
BigQueryClient bigQueryClient;

@Mock
@SuppressWarnings("unused") // Blir faktisk brukt
private MetricService metricService;
Expand Down
2 changes: 2 additions & 0 deletions src/test/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,7 @@ pdl.scope=api://dev-fss.pdl.pdl-api/.default

spring.cloud.gateway.mvc.enabled=false

gcp.projectId=test

app.env.kassering.godkjenteIdenter=Z999999
shedlock.lockAtLeastFor=PT0S

0 comments on commit aea2d72

Please sign in to comment.