Not able populating the method and etc for Stackdriver Trace - google-cloud-stackdriver

I am new to Stackdriver Trace. I am not sure what I am doing wrong if can somebody point me to right direction. I would really appreciate. Basicall I am not able populate methods and such from Request
...
var ctx context.Context
var span *trace.Span
if sc, ok := hf.SpanContextFromRequest(r); ok {
ctx, span = trace.StartSpanWithRemoteParent(r.Context(), "internal.platform.web", sc)
} else {
ctx, span = trace.StartSpan(r.Context(), "internal.platform.web")
}
defer span.End()
...
...
Here is what I see at Dashboard View.
I can see my midleware can logging.
2019/02/17 20:39:41.976194 logger.go:25: 277f1b2d7d870603d5693333e7594a81 : (200) : GET /dev/v1/health -> 10.28.0.1:60580 (127.269µs)
2019/02/17 20:39:45.148052 logger.go:25: 98efb55e9c5dc093e107cf356668099a : (200) : GET /dev/v1/health -> 10.28.0.1:44956 (93.801µs)
2019/02/17 20:40:58.019661 logger.go:25: 1b714a54e80cef85bec6c5b65d25cebb : (200) : GET /dev/v1/health -> 10.28.0.1:49086 (99.875µs)
2019/02/17 20:41:29.917161 logger.go:25: 0826c046716a1f333eab9d1c762e1561 : (200) : GET /dev/v1/health -> 10.28.0.1:52910 (98.377µs)
2019/02/17 20:42:11.988756 logger.go:25: 6870a9ea2cac0493aab1e472ce895bbf : (200) : GET /dev/v1/health -> 10.28.0.1:57362 (113.634µs)
2019/02/17 20:42:15.165058 logger.go:25: f7b77d80452ae686f15001e663187004 : (200) : GET /dev/v1/health -> 10.28.0.1:42420 (142.178µs)

Apparently, I need to use ochttp plugin for OpenCensus instrumentation for net/http package. That covers all attributes on the span.

Related

Spring WebFlux - WebGraphQlInterceptor has empty request data

I would need to retrieve data from query headers for use in the GraphQl query controller. I searched around a bit and found the WebGraphQlInterceptor, but realized that when the WebGraphQlRequest argument is invoked it is completely devoid of information.
For example, this code:
#Component
class WebRequestInterceptor : WebGraphQlInterceptor {
val logger: Logger by lazy { LoggerFactory.getLogger(WebRequestInterceptor::class.java) }
override fun intercept(request: WebGraphQlRequest, chain: WebGraphQlInterceptor.Chain): Mono<WebGraphQlResponse> {
logger.info("URI", request.uri.toString())
logger.info("HEADERS", request.headers.toString())
logger.info("DOCUMENT", request.document)
return chain.next(request)
}
}
Returns:
2022-09-12 10:57:11.747 INFO 1 --- [or-http-epoll-1] b.s.b.gateway.auth.WebRequestInterceptor : URI *empty string*
2022-09-12 10:57:11.748 INFO 1 --- [or-http-epoll-1] b.s.b.gateway.auth.WebRequestInterceptor : HEADERS *empty string*
2022-09-12 10:57:11.748 INFO 1 --- [or-http-epoll-1] b.s.b.gateway.auth.WebRequestInterceptor : DOCUMENT *empty string*
P.S. The same thing happens if I try to log a single headers element using the request.headers.getFirst(..) function.

DynamoDB - Error is ResourceNotFoundException but cast fails in Go

I wrote some code to attempt to get a table description in Go, using the AWS SDK V2 DynamoDB package:
// First, create a connection to our local DynamoDB
client := dynamodb.NewFromConfig(cfg)
// Next, attempt to get the table description associated with the table name
output, err := client.DescribeTable(ctx, &dynamodb.DescribeTableInput{
TableName: table.TableName,
})
// Now, if we got an error then check if it was a resource-not-found exception. If
// it was then that means we should create the table; otherwise, it means that something
// isn't right so return it. If the description was nil, we'll also create the table
var create bool
if err != nil {
if _, ok := err.(*types.ResourceNotFoundException); !ok {
return err
} else {
create = true
}
} else if output == nil {
create = true
}
During testing, this code returned the following error:
operation error DynamoDB: DescribeTable, https response error StatusCode: 400, RequestID: 4b0bcb2b-c833-459f-9db2-54841aa1bbd3, ResourceNotFoundException
The problem I'm having is that this is clearly a ResourceNotFoundException but the cast is not working. Is there something else I need to do to get this to work?
I have found a solution. First, one of the issues I had was that I was importing github.com/aws/aws-sdk-go-v2/service/sso/types instead of github.com/aws/aws-sdk-go-v2/service/dynamodb/types so my cast would never have worked. That being said, making this change did not fix the issue.
After log-debugging, I discovered that the v2 SDK wraps the AWS errors in a *smithy.OperationError type. Therefore, direct-casting and errors.Is won't work.
What I did that actually worked here was to change my error checking code to this:
if temp := new(types.ResourceNotFoundException); !errors.As(err, &temp) {
return err
} else {
create = true
}

How do I get a byte[] (image) from a webservice using micronaunt HttpClient

I am porting a Grails 3.1 library for using some internal webservices to Grails 4.0. One of the services provides an image of a requested employee upon request. I am having difficulty implementing the (micronaut) HttpClient code to process the request - specifically to get a proper byte[] that is the returned image.
A simple curl command on the command line works with the service:
curl -D headers.txt -H 'Authorization:Basic <encodedKeyHere>' https:<serviceUrl> >> image.jpg
and the image is correct. The header.txt is:
HTTP/1.1 200
content-type: image/jpeg;charset=UTF-8
date: Tue, 27 Aug 2019 20:05:43 GMT
x-ratelimit-limit: 100
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
x-ratelimit-remaining: 99
X-RateLimit-Reset: 38089
x-ratelimit-reset: 15719
Content-Length: 11918
Connection: keep-alive
The old library uses the groovyx.net.http.HTTPBuilder and simply does:
http.request(Method.GET, ContentType.BINARY) {
uri.path = photoUrlPath
uri.query = queryString
headers.'Authorization' = "Basic $encoded".toString()
response.success = { resp, inputstream ->
log.info "response status: ${resp.statusLine}"
return ['status':resp.status, 'body':inputstream.getBytes()]
}
response.failure = { resp ->
return ['status':resp.status,
'error':resp.statusLine.reasonPhrase,
body:resp.getEntity().getContent().getText()]
}
}
so returning the bytes from an inputStream. This works.
I've tried several things using the micronaut HttpClient, both with the low level API and with the declarative API.
A simple example with the declarative API:
#Get(value='${photo.ws.pathurl}', produces = MediaType.IMAGE_JPEG)
HttpResponse<byte[]> getPhoto(#Header ('Authorization') String authValue,
#QueryValue("emplId") String emplId)
And than in the Service:
HttpResponse<byte[]> resp = photoClient.getPhoto(getBasicAuth(),emplId)
def status = resp.status() // code == 200 --> worked
def bodyStrOne = resp.getBody() // nope: get Optional.empty
// Tried different getBody(class) -> Can't figure out where the byte[]s are
// For example can do:
def buf = resp.getBody(io.netty.buffer.ByteBuf).value // Why need .value?
def bytes = buf.readableBytes() // Returns 11918 --> the expected value
byte[] ans = new byte[buf.readableBytes()]
buf.readBytes(ans) // Throws exception: io.netty.util.IllegalReferenceCountException: refCnt: 0
This "works" but the returned String looses some encoding that I can't reverse:
// Client - use HttpResponse<String>
#Get(value='${photo.ws.pathurl}', produces = MediaType.IMAGE_JPEG)
HttpResponse<String> getPhoto(#Header ('Authorization') String authValue,
#QueryValue("emplId") String emplId)
// Service
HttpResponse<String> respOne = photoClient.getPhoto(getBasicAuth(),emplId)
def status = respOne.status() // code == 200 --> worked
def bodyStrOne = respOne.getBody(String.class) // <-- RETURNS DATA..just NOT an Image..or encoded or something
String str = bodyStrOne.value // get the String data
// But these bytes aren't correct
byte[] ans = str.getBytes() // NOT an image..close but not.
// str.getBytes(StandardCharsets.UTF_8) or any other charset doesn't work
Everything I've tried with the ByteBuf classes throws the io.netty.util.IllegalReferenceCountException: refCnt: 0 exception.
Any direction/help would be greatly appreciated.
Running:
Grails 4.0
JDK 1.8.0_221
Groovy 2.4.7
Windows 10
IntellJ 2019.2
It must be Grails bug.
Add this line into logback.groovy:
logger("io.micronaut.http", TRACE)
Then you should see that the body was not empty but finally it ends with error Unable to convert response body to target type class [B. See the trace:
2019-09-11 11:19:16.235 TRACE --- [ntLoopGroup-1-4] i.m.http.client.DefaultHttpClient : Status Code: 200 OK
2019-09-11 11:19:16.235 TRACE --- [ntLoopGroup-1-4] i.m.http.client.DefaultHttpClient : Content-Type: image/jpeg
2019-09-11 11:19:16.235 TRACE --- [ntLoopGroup-1-4] i.m.http.client.DefaultHttpClient : Content-Length: 11112
2019-09-11 11:19:16.237 TRACE --- [ntLoopGroup-1-4] i.m.http.client.DefaultHttpClient : Accept-Ranges: bytes
2019-09-11 11:19:16.237 TRACE --- [ntLoopGroup-1-4] i.m.http.client.DefaultHttpClient : Response Body
2019-09-11 11:19:16.237 TRACE --- [ntLoopGroup-1-4] i.m.http.client.DefaultHttpClient : ----
2019-09-11 11:19:16.238 TRACE --- [ntLoopGroup-1-4] i.m.http.client.DefaultHttpClient : ���� C
...
2019-09-11 11:19:16.241 TRACE --- [ntLoopGroup-1-4] i.m.http.client.DefaultHttpClient : ----
2019-09-11 11:19:16.243 TRACE --- [ntLoopGroup-1-4] i.m.http.client.DefaultHttpClient : Unable to convert response body to target type class [B
But when you try the same in standalone Microunaut application (add <logger name="io.micronaut.http" level="trace"/> into logback.xml) the result is different:
09:02:48.583 [nioEventLoopGroup-1-5] TRACE i.m.http.client.DefaultHttpClient - Status Code: 200 OK
09:02:48.583 [nioEventLoopGroup-1-5] TRACE i.m.http.client.DefaultHttpClient - Content-Type: image/jpeg
09:02:48.589 [nioEventLoopGroup-1-5] TRACE i.m.http.client.DefaultHttpClient - content-length: 23195
09:02:48.590 [nioEventLoopGroup-1-5] TRACE i.m.http.client.DefaultHttpClient - Response Body
09:02:48.590 [nioEventLoopGroup-1-5] TRACE i.m.http.client.DefaultHttpClient - ----
09:02:48.612 [nioEventLoopGroup-1-5] TRACE i.m.http.client.DefaultHttpClient - ���� C���
...
09:02:48.620 [nioEventLoopGroup-1-5] TRACE i.m.http.client.DefaultHttpClient - ----
Micronaut trace has no error.
Here is an example of declarative HTTP client which downloads random image from https://picsum.photos web site:
import io.micronaut.http.HttpResponse
import io.micronaut.http.MediaType
import io.micronaut.http.annotation.Get
import io.micronaut.http.client.annotation.Client
#Client('https://picsum.photos')
interface LoremPicsumClient {
#Get(value = '{width}/{height}', produces = MediaType.IMAGE_JPEG)
HttpResponse<byte[]> getImage(Integer width, Integer height)
}
And Spock unit test for it:
import io.micronaut.http.HttpStatus
import io.micronaut.test.annotation.MicronautTest
import spock.lang.Specification
import javax.inject.Inject
import java.nio.file.Files
import java.nio.file.Paths
#MicronautTest
class LoremPicsumClientSpec extends Specification {
#Inject
LoremPicsumClient client
void 'image is downloaded'() {
given:
def output = Paths.get('test')
when:
def response = client.getImage(300, 200)
then:
response.status == HttpStatus.OK
response.getBody().isPresent()
when:
Files.write(output, response.getBody().get())
then:
Files.probeContentType(output) == 'image/jpeg'
}
}
In Micronaut the test passes and an image is saved into the test file. But in Grails the test fails because HttpClient is not able to convert the response bytes into byte array or better into anything else then String.
We are currently using this implementation:
#Client(value = "\${image-endpoint}")
interface ImageClient {
#Get("/img")
fun getImageForAddress(
#QueryValue("a") a: String
): CompletableFuture<ByteArray>
}
works fine for us.
When I use the HttpResponse I get an error as well, couldn't make it work with that.
Documentation propose to send bytes via input stream but I didn't manage to make it work. The most brittle thing that HttpClient should Consume bytes but Server should Produce.
#Get(value = "/write", produces = MediaType.TEXT_PLAIN)
HttpResponse<byte[]> write() {
byte[] bytes = "test".getBytes(StandardCharsets.UTF_8);
return HttpResonse.ok(bytes); //
}

Sentry Go Integration, how to specify error level?

According to the official docs https://docs.sentry.io/clients/go/ you can log errors in Sentry from a golang project with:
// For Errors
raven.CapturePanic(func() {
// do all of the scary things here
}, nil)
// For panic
if err != nil {
raven.CaptureErrorAndWait(err, nil)
log.Panic(err)
}
This works like a charm, the problem is in Sentry both functions are logged with level 'Error'. Anyone knows how can the logging level be specified for each call? In Python is very explicit, but I don't see it for Go.
Using the sentry-go SDK, the Level is set on the Scope.
Documentation:
https://pkg.go.dev/github.com/getsentry/sentry-go?tab=doc#Scope.SetLevel
https://pkg.go.dev/github.com/getsentry/sentry-go?tab=doc#Level
Example:
sentry.WithScope(func(scope *sentry.Scope) {
scope.SetLevel(sentry.LevelFatal)
sentry.CaptureException(errors.New("example error"))
})
I followed the advice in the comments, and came up with this:
// sentryErrorCapture sends error data to Sentry asynchronously. Use for non-Fatal errors.
var sentryErrorCapture = func(err error, severity raven.Severity, tags map[string]string, interfaces ...raven.Interface) string {
packet := newSentryPackage(err, severity, tags, interfaces...)
eventID, _ := raven.Capture(packet, tags)
return eventID
}
func newSentryPackage(err error, severity raven.Severity, tags map[string]string, interfaces ...raven.Interface) (packet *raven.Packet) {
interfaces = append(interfaces,
raven.NewException(err, raven.GetOrNewStacktrace(err, 1, 3, raven.IncludePaths())))
packet = &raven.Packet{
Message: err.Error(),
Level: severity,
Interfaces: interfaces,
Extra: getSentryExtraInfo(),
}
return
}
When I want to log an error specifying the level I call: sentryErrorCapture(err, raven.ERROR, nil).

How do I enable CORS in Giraffe?

I am unable to successfully perform a Post operation using the Giraffe framework on the server with an Elm client sending the request.
I receive the following message when attempting to test an http request:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost1
Request starting HTTP/1.1 OPTIONS http://localhost:5000/register 0
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request
starting HTTP/1.1 OPTIONS http://localhost:5000/register 0 dbug:
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware1
OPTIONS requests are not supported
The service implementation is the following:
let private registrationHandler =
fun(context: HttpContext) ->
async {
let! data = context.BindJson<RegistrationRequest>()
match register data with
| Success profile -> return! json profile context
| Failure -> return! (setStatusCode 400 >=> json "registration failed") context
}
I then attempted the following and observed the same result:
let private registrationHandler =
fun(context: HttpContext) ->
async {
return! text "hello world" context
}
Appendix:
POST >=>
choose [
route "/register" >=> registrationHandler
]
The source file can be found here.
Elm and CORS
WebAPI enable Cors
Here's a Giraffe sample that shows the code for supporting Cors.
Add package: Microsoft.AspNetCore.Cors
In .fs file add:
open Microsoft.AspNetCore.Cors
Add UseCors e.g.:
let configureApp (app : IApplicationBuilder) =
app.UseGiraffeErrorHandler errorHandler
app.UseStaticFiles() |> ignore
app.UseAuthentication() |> ignore
app.UseCors(Action<_>(fun (b: Infrastructure.CorsPolicyBuilder) -> b.AllowAnyHeader() |> ignore; b.AllowAnyMethod() |> ignore)) |> ignore
app.UseGiraffe webApp
In services add cors:
let configureServices (services : IServiceCollection) =
let sp = services.BuildServiceProvider()
let env = sp.GetService<IHostingEnvironment>()
let viewsFolderPath = Path.Combine(env.ContentRootPath, "Views")
services
.AddCors()
.AddAuthentication(authScheme)
.AddCookie(cookieAuth)
|> ignore

Resources