Skip to content

Commit

Permalink
Merge pull request #860 from iRevive/sdk-exporter/private-proto-models
Browse files Browse the repository at this point in the history
sdk-exporter: generate proto models in the private package
  • Loading branch information
iRevive authored Dec 5, 2024
2 parents f4f7cec + 6f5b298 commit e5780ad
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 17 deletions.
4 changes: 4 additions & 0 deletions .scalafix.conf
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ OrganizeImports {
importSelectorsOrder = SymbolsFirst
removeUnused = false
}

triggered.rules = [
NoPublicClasses
]
45 changes: 44 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import com.typesafe.tools.mima.core._

ThisBuild / tlBaseVersion := "0.11"
ThisBuild / tlBaseVersion := "0.12"

ThisBuild / organization := "org.typelevel"
ThisBuild / organizationName := "Typelevel"
Expand Down Expand Up @@ -376,16 +376,59 @@ lazy val `sdk-exporter-proto` =
Compile / PB.targets ++= Seq(
scalapb.gen(grpc = false) -> (Compile / sourceManaged).value / "scalapb"
),
Compile / PB.generate := {
val files = (Compile / PB.generate).value

files.filter(_.isFile).foreach { file =>
val content = IO.read(file)

// see: https://github.com/scalapb/ScalaPB/issues/1778
val updated = content
.replaceAll(
"""(?m)^object (\w+) extends _root_\.scalapb\.GeneratedEnumCompanion\[\w+\]""",
"private[exporter] object $1 extends _root_.scalapb.GeneratedEnumCompanion[$1]"
)
.replaceAll(
"""(?m)^object (\w+) extends _root_\.scalapb\.GeneratedFileObject""",
"private[exporter] object $1 extends _root_.scalapb.GeneratedFileObject"
)

IO.write(file, updated)
}

files
},
scalacOptions := {
val opts = scalacOptions.value
if (tlIsScala3.value) opts.filterNot(_ == "-Wvalue-discard") else opts
},
// We use open-telemetry protobuf spec to generate models
// See https://scalapb.github.io/docs/third-party-protos/#there-is-a-library-on-maven-with-the-protos-and-possibly-generated-java-code
libraryDependencies ++= Seq(
"com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf",
"io.opentelemetry.proto" % "opentelemetry-proto" % OpenTelemetryProtoVersion % "protobuf-src" intransitive ()
)
)
.jvmSettings(
// scalafix settings to ensure there are no public classes in the module
// run scalafix against generated sources
Compile / ScalafixPlugin.autoImport.scalafix / unmanagedSources := (Compile / managedSources).value,
// run scalafix only on scala 2.13
scalafixOnCompile := !tlIsScala3.value,
// read scalafix rules from a shared folder
ScalafixConfig / sourceDirectory := {
if (tlIsScala3.value) {
(ScalafixConfig / sourceDirectory).value
} else {
baseDirectory.value.getParentFile / "src" / "scalafix"
}
},
// required by scalafix rules
libraryDependencies ++= {
if (tlIsScala3.value) Nil
else Seq("ch.epfl.scala" %% "scalafix-core" % _root_.scalafix.sbt.BuildInfo.scalafixVersion % ScalafixConfig)
}
)
.settings(scalafixSettings)

lazy val `sdk-exporter-common` =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import fs2.Stream
import fs2.compression.Compression
import fs2.io.net.Network
import fs2.io.net.tls.TLSContext
import io.opentelemetry.proto.collector.trace.v1.trace_service.ExportTraceServiceResponse
import org.http4s.ContentCoding
import org.http4s.EntityEncoder
import org.http4s.Header
Expand All @@ -57,6 +56,7 @@ import org.typelevel.otel4s.sdk.exporter.RetryPolicy
import org.typelevel.otel4s.sdk.exporter.otlp.grpc.GrpcCodecs
import org.typelevel.otel4s.sdk.exporter.otlp.grpc.GrpcHeaders
import org.typelevel.otel4s.sdk.exporter.otlp.grpc.GrpcStatusException
import org.typelevel.otel4s.sdk.exporter.proto.trace_service.ExportTraceServiceResponse
import scalapb_circe.Printer
import scodec.Attempt
import scodec.DecodeResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ package sdk
package exporter.otlp

import io.circe.Json
import io.opentelemetry.proto.common.v1.common.{InstrumentationScope => ScopeProto}
import io.opentelemetry.proto.common.v1.common.AnyValue
import io.opentelemetry.proto.common.v1.common.ArrayValue
import io.opentelemetry.proto.common.v1.common.KeyValue
import io.opentelemetry.proto.resource.v1.resource.{Resource => ResourceProto}
import org.typelevel.otel4s.sdk.common.InstrumentationScope
import org.typelevel.otel4s.sdk.exporter.proto.common.{InstrumentationScope => ScopeProto}
import org.typelevel.otel4s.sdk.exporter.proto.common.AnyValue
import org.typelevel.otel4s.sdk.exporter.proto.common.ArrayValue
import org.typelevel.otel4s.sdk.exporter.proto.common.KeyValue
import org.typelevel.otel4s.sdk.exporter.proto.resource.{Resource => ResourceProto}
import scalapb.GeneratedMessage
import scalapb_circe.Printer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package org.typelevel.otel4s.sdk.exporter.otlp
import io.circe.Encoder
import io.circe.Json
import io.circe.syntax._
import io.opentelemetry.proto.common.v1.common.KeyValue
import munit.ScalaCheckSuite
import org.scalacheck.Arbitrary
import org.scalacheck.Prop
Expand All @@ -29,6 +28,7 @@ import org.typelevel.otel4s.AttributeType
import org.typelevel.otel4s.Attributes
import org.typelevel.otel4s.sdk.TelemetryResource
import org.typelevel.otel4s.sdk.common.InstrumentationScope
import org.typelevel.otel4s.sdk.exporter.proto.common.KeyValue
import org.typelevel.otel4s.sdk.scalacheck.Arbitraries._
import scalapb_circe.Printer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ package exporter.otlp.metrics

import com.google.protobuf.ByteString
import io.circe.Json
import io.opentelemetry.proto.collector.metrics.v1.metrics_service.ExportMetricsServiceRequest
import io.opentelemetry.proto.metrics.v1.{metrics => Proto}
import io.opentelemetry.proto.metrics.v1.metrics.ResourceMetrics
import io.opentelemetry.proto.metrics.v1.metrics.ScopeMetrics
import org.typelevel.otel4s.sdk.exporter.otlp.ProtoEncoder
import org.typelevel.otel4s.sdk.exporter.proto.{metrics => Proto}
import org.typelevel.otel4s.sdk.exporter.proto.metrics.ResourceMetrics
import org.typelevel.otel4s.sdk.exporter.proto.metrics.ScopeMetrics
import org.typelevel.otel4s.sdk.exporter.proto.metrics_service.ExportMetricsServiceRequest
import org.typelevel.otel4s.sdk.metrics.data.AggregationTemporality
import org.typelevel.otel4s.sdk.metrics.data.ExemplarData
import org.typelevel.otel4s.sdk.metrics.data.MetricData
Expand Down
43 changes: 43 additions & 0 deletions sdk-exporter/proto/src/main/protobuf/package.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
syntax = "proto3";

package opentelemetry.proto;

import "scalapb/scalapb.proto";

// OpenTelemetry proto models are defined at https://github.com/open-telemetry/opentelemetry-proto.
// By default, generated models are public, which makes them accessible on the classpath.
//
// This poses a significant problem because opentelemetry-proto may introduce binary-breaking changes.
// As a result, any updates to the opentelemetry-proto can cause otel4s-sdk-exporter-proto to break binary compatibility.
//
// That's why we must generate them package-private.
//
// See: https://github.com/scalapb/ScalaPB/issues/1778, https://github.com/typelevel/otel4s/pull/860
//
// Docs:
// https://scalapb.github.io/docs/faq/#how-do-i-mark-a-generated-case-class-private
// https://scalapb.github.io/docs/customizations/#auxiliary-options
option (scalapb.options) = {
scope: PACKAGE

// override the package, so we can access the models
package_name: "org.typelevel.otel4s.sdk.exporter.proto"

aux_message_options: [
{
target: "*"
options: {
annotations: "private[exporter]"
companion_annotations: "private[exporter]"
}
}
]
aux_enum_options: [
{
target: "*"
options: {
base_annotations: "private[exporter]"
}
}
]
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fix.NoPublicClasses
30 changes: 30 additions & 0 deletions sdk-exporter/proto/src/scalafix/scala/fix/NoPublicClasses.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package fix

import scalafix.v1._
import scala.meta._

class NoPublicClasses extends SyntacticRule("NoPublicClasses") {
override def description: String = "Disallows public classes and objects in the module"

override def fix(implicit doc: SyntacticDocument): Patch = {
doc.tree.collect {
case defn: Defn.Class if !defn.mods.exists(_.is[Mod.Private]) && defn.parent.exists(_.is[Pkg.Body]) =>
Patch.lint(
Diagnostic(
id = "NoPublicClasses",
message = "Public classes are not allowed in this module.",
position = defn.pos
)
)

case defn: Defn.Object if !defn.mods.exists(_.is[Mod.Private]) && defn.parent.exists(_.is[Pkg.Body]) =>
Patch.lint(
Diagnostic(
id = "NoPublicClasses",
message = "Public objects are not allowed in this module.",
position = defn.pos
)
)
}.asPatch
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ package trace

import com.google.protobuf.ByteString
import io.circe.Json
import io.opentelemetry.proto.collector.trace.v1.trace_service.ExportTraceServiceRequest
import io.opentelemetry.proto.trace.v1.trace.{Span => SpanProto}
import io.opentelemetry.proto.trace.v1.trace.{Status => StatusProto}
import io.opentelemetry.proto.trace.v1.trace.ResourceSpans
import io.opentelemetry.proto.trace.v1.trace.ScopeSpans
import org.typelevel.otel4s.sdk.exporter.proto.trace.{Span => SpanProto}
import org.typelevel.otel4s.sdk.exporter.proto.trace.{Status => StatusProto}
import org.typelevel.otel4s.sdk.exporter.proto.trace.ResourceSpans
import org.typelevel.otel4s.sdk.exporter.proto.trace.ScopeSpans
import org.typelevel.otel4s.sdk.exporter.proto.trace_service.ExportTraceServiceRequest
import org.typelevel.otel4s.sdk.trace.data.EventData
import org.typelevel.otel4s.sdk.trace.data.LinkData
import org.typelevel.otel4s.sdk.trace.data.SpanData
Expand Down

0 comments on commit e5780ad

Please sign in to comment.