Saturday, July 15, 2023

Coursera and verifying ID with Persona

It was a total nightmare being able to verify my Id with Coursera. Coursera will not issue a certificate unless you verify your Id. It turned out that Coursera/Persona doesn't recognize my Italian Paper Id - probably because it's not in Credic Card format. And It doesn't recognize my Residence Permit in Switzerland. After a LOT of attempts it accepted my Swiss Driving License. It's totally disappointing that they don't allow you to tal to a human, all is determined by these automated procedures. If you think that the AI-dominated world will be a Paradise, think twice, an Algorythm will decide of your life. Worst of the orwellian nightmares.

springdoc-openapi-maven-plugin

I will guide you to build a simple RESTful web service using Spring Boot, and then we will generate the OpenAPI 3.0 documentation using the springdoc-openapi-maven-plugin. Step 1: Setup Spring Boot Project Create a new Spring Boot project. You can use Spring Initializr (https://start.spring.io/) for easy bootstrapping of your project. For the dependencies, select: Web JPA H2 (for simplicity, we're using an in-memory database) Springdoc OpenAPI UI Step 2: Create the application.properties In src/main/resources/application.properties, add the following configuration:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
Step 3: Create a simple Entity Create a Student class in your project:
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Student {

    @Id
    private String id;
    private String name;

    // getters and setters
}
Step 4: Create a JPA Repository Create an interface StudentRepository that extends JpaRepository:
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository extends JpaRepository<Student, String> {}
Step 5: Create a REST Controller Create a StudentController class:
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/students")
public class StudentController {

    private final StudentRepository repository;

    public StudentController(StudentRepository repository) {
        this.repository = repository;
    }

    @GetMapping
    public List<Student> getAllStudents() {
        return repository.findAll();
    }

    @PostMapping
    public Student newStudent(@RequestBody Student newStudent) {
        return repository.save(newStudent);
    }
}
Step 6: Generating OpenAPI 3.0 docs Add the springdoc-openapi-maven-plugin to your pom.xml:
  
<plugin>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-maven-plugin</artifactId>
    <version>1.5</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <phase>compile</phase>
            <configuration>
                <apiDocsUrl>http://localhost:8080/v3/api-docs</apiDocsUrl>
                <outputFileName>openapi.json</outputFileName>
                <outputDir>${project.build.directory}</outputDir>
            </configuration>
        </execution>
    </executions>
</plugin>
This will generate an openapi.json file in your target directory whenever you compile your project. Now when you run your application and go to http://localhost:8080/swagger-ui.html, you should see the OpenAPI UI with your API documented. You can use the UI to send requests and see the responses. Remember to start your application before generating the documentation, because the plugin makes an actual HTTP request to the /v3/api-docs endpoint to generate the OpenAPI specification. Please be aware that as of my knowledge cut-off in September 2021, the above mentioned plugin and setup were in use. Please ensure that you're using up-to-date versions and configurations by checking the official documentation.

openapi-generator-maven-plugin

The openapi-generator-maven-plugin is a plugin for the Apache Maven project management tool, which is used to build and manage projects written in Java and other languages. This plugin specifically aids in the generation of API clients, server stubs, API documentation, and configuration from an OpenAPI Specification (formerly known as the Swagger Specification). An OpenAPI Specification is a standard, language-agnostic way of describing HTTP-based APIs, allowing both humans and machines to understand the capabilities of a service without having to read the source code or access documentation. Here is an example of how the openapi-generator-maven-plugin might be configured in your pom.xml:

<build>
  <plugins>
    <plugin>
      <groupId>org.openapitools</groupId>
      <artifactId>openapi-generator-maven-plugin</artifactId>
      <version>4.3.1</version> <!-- use the latest version available -->
      <executions>
        <execution>
          <goals>
            <goal>generate</goal>
          </goals>
          <configuration>
            <inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec>
            <generatorName>java</generatorName>
            <configOptions>
              <sourceFolder>src/gen/java/main</sourceFolder>
            </configOptions>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

In the configuration above, the inputSpec tag is used to specify the location of the API specification file. The generatorName tag is used to specify the language of the generated code, in this case, Java. The configOptions tag is used to specify various options for the generated code, such as its location within the project. After this plugin is set up and the project is built (for instance, with mvn install), the API clients, server stubs, and other generated code are produced automatically based on the API specification file. This can significantly streamline the development process when working with APIs. Please note the plugin version in the example is hypothetical and might be outdated at the time of your query. You should always try to use the latest available version.

Saturday, July 8, 2023

AI and Deep Learning courses

Someone deeply recommended me this Coursera course https://www.coursera.org/learn/neural-networks-deep-learning/ , for me it turned out to be quite disappointing, the lessons show lot of formulas with hardly any example, they don't communicate passion and interest, and they are totally in the wrong order in relation to the practical tests, so you have to take a test before the theory has been explained.
The exercises are useful, but you can find them here and you can practice in here https://jupyter.org/try .
Some exercises are also available here https://github.com/Kulbear/deep-learning-coursera/blob/master/Neural%20Networks%20and%20Deep%20Learning/Week%203%20Quiz%20-%20Shallow%20Neural%20Networks.md
Someone recommended me a textbook Deep Learning by Ian Goodfellow, inventor of generative networks. But it is very theoretical. There's a very nice course on YouTube from NYU and it's by Alfredo Canziani and Yann LeCun who's the guy who invented convolutional networks. There is a channel called Deep Lizard which has a course on PyTorch which is a framework to make neural networks.

Tuesday, June 13, 2023

AI-900 exam

https://youtu.be/edEfRpQSjXs excellent video with questions and answers (skip first 20 minutes)

https://learn.microsoft.com/en-us/certifications/exams/ai-900/ official doc



This also is watchable, although lot of blablabla https://youtu.be/OwZHNH8EfSU

Sample questions here https://www.kasolution.com.br/cp/AI-900-SampleQuestions.pdf



Fun with jhipster

Precious video to get started:

https://www.youtube.com/watch?v=uQqlO3IGpTU&ab_channel=MattRaible

remember to set your postgres password in src/main/resources/config/application-dev.yml

Then you can start your @SpringBootApplication application, and "npm start" and http://localhost:9000 and login as admin/admin

(when running in DEV locally, it doesn't seem to be able to send emails to authenticate new users)

You can now use https://github.com/mraible/jhipster6-demo/blob/master/blog.jdl to populate the DB.



Tuesday, May 9, 2023

React menus

So far in React tutorials I have seen only tiny applications with a very simple menu system.
Menus are simply hardcoded, maybe using React Router to simplify a bit the navigation.

A real life enterprise application will be MUCH more complex than that.

I have asked ChatGPT:
"I need to build a large UI application with a complex menu system. What is the current industry standard to maintain the menu items?"

Here is the answer - which is quite decent IMHO:

There are several approaches to maintaining menu items in a large UI application with a complex menu system, and the industry standard can vary depending on the specific requirements and technologies used in the project. However, here are a few common approaches:

Data-driven menus: In this approach, the menu items are stored in a database or other data source and retrieved dynamically by the application at runtime. This allows for greater flexibility in managing the menu items, as changes can be made to the data source without having to update the application code.

Component-based menus: Another approach is to build the menu system as a set of reusable components that can be composed and reused across different parts of the application. This can make it easier to maintain the menu items, as changes can be made to the components and propagated throughout the application.

Configuration-based menus: In this approach, the menu items are defined in configuration files or other external files that can be easily modified without having to modify the application code. This can make it easier to maintain the menu items, as changes can be made without requiring a code release.

Code-based menus: Finally, some applications may choose to maintain the menu items directly in code. While this can be more difficult to maintain, it can also provide greater control and customization over the menu system.

Ultimately, the best approach will depend on the specific requirements and constraints of the project. It may be helpful to consult with experienced UI developers and architects to determine the most appropriate approach for your particular use case.


Saturday, May 6, 2023

Swagger 2.0 vs OpenAPI 3.0, conversion

https://swagger.io/docs/specification/2-0/basic-structure/ Swagger 2.0 specifications

https://swagger.io/docs/specification/basic-structure/ OpenAPI 3.0 specifications

https://editor.swagger.io/ Swagger Editor, it contains a menu to translate 2.0 into 3.0, but this works by sending the yaml to a remote conversion service, so it might not work in your premises. You can also install the container with swagger-editor https://hub.docker.com/r/swaggerapi/swagger-editor/ , but make sure that external connectoins are legal in your company.



Friday, April 7, 2023

Functions vs Components in React, and useState

useState example:
import React, {useState} from 'react'

export default function Counter({initialCount}) {
    const [count, setCount] = useState(initialCount)
    return (
        <div>
            <button onClick = {() => setCount(prevCount => prevCount - 1)}>-</button>
            <span>{count}</span>
            <button onClick = {() => setCount(prevCount => prevCount + 1)}>+</button>
        </div>
    )
}


same thing using Component


import React, { Component } from 'react'

export default class Counter extends Component {

    constructor(props){
        super(props);
        this.state = {
            count: props.initialCount
        }
    }

    render() {
        return (
            <div>
                <button onClick={() => this.changeCount(-1)}>-</button>
                <span>{this.state.count}</span>
                <button onClick={() => this.changeCount(1)}>+</button>
            </div>
        )
    }

    changeCount(amount) {
        this.setState(prevState => {return { count: prevState.count + amount}})
    }

}



Popular VSCode Extensions for React

https://www.syncfusion.com/blogs/post/7-vs-code-extensions-for-react-developers.aspx

Friday, March 31, 2023

Monday, March 27, 2023

ChatGPT in ESLint (I will soon lose my job, replaced by this little bastard...)

Question: 

 

please write a ESLint rule to flag as deprecated the usage of variable names like Button.size.NORMAL

Answer:


To write an ESLint rule to flag the usage of variable names like Button.size.NORMAL, you can use the following code:

vbnet

module.exports = {
  rules: {
    "no-deprecated-variable-name": {
      meta: {
        deprecated: true,
        type: "problem"
      },
      create: function(context) {
        return {
          MemberExpression(node) {
            const { object, property } = node;
            if (object.type === "Identifier" && object.name === "Button" &&
                property.type === "MemberExpression" && property.property.name === "NORMAL") {
              context.report({
                node: property.property,
                message: "The use of 'Button.size.NORMAL' is deprecated. Use a different value instead."
              });
            }
          }
        };
      }
    }
  }
};

This rule creates a new ESLint rule called no-deprecated-variable-name, which checks for the usage of Button.size.NORMAL variables. When the rule encounters this variable, it reports a warning message to the user indicating that the usage of this variable is deprecated and suggests using a different value instead.

To use this rule, you will need to add it to your .eslintrc configuration file:

json

{
  "rules": {
    "no-deprecated-variable-name": "warn"
  }
}

In this configuration, the rule is set to "warn", which means it will produce a warning message but will not fail the build. You can set it to "error" to make it fail the build.




Sunday, March 19, 2023

Reverse Proxy with Docker httpd container on Windows

 https://www.middlewareinventory.com/blog/docker-reverse-proxy-example/

 

I have followed these instructions for Windows and it works, the only change I had to do is to start the container with the  "--net=host" options, and from the container I had to configure the ReverseProxyPass to use the IP address of the host (NOT the WSL IP).



Reverse Proxy with Spring Boot

https://github.com/vernetto/myreverseproxy/blob/master/src/main/java/org/pierre/myreverseproxy/CharonConfiguration.java 

 

I really like the simplicity and power of this CHARON, a Spring Boot- based Swiss knife for load balancing and request forwarding. 

 

Here a lot more examples https://github.com/mkopylec/charon-spring-boot-starter/blob/master/charon-spring-webmvc/src/test/java/com/github/mkopylec/charon/test/ReverseProxyConfiguration.java  



Saturday, March 18, 2023

Reverse Proxy with nodejs

https://github.com/http-party/node-http-proxy
npm install http-proxy --save
node .\server.js

var http = require('http'),
    httpProxy = require('http-proxy');
//
// Create your proxy server and set the target in the options.
//
httpProxy.createProxyServer({target:'http://localhost:10090'}).listen(8000);




Docker container connecting to host service on Windows

docker run -d -p 80:80 --name webserver nginx
docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                NAMES
2733688156aa   nginx     "/docker-entrypoint.…"   14 seconds ago   Up 13 seconds   0.0.0.0:80->80/tcp   webserver


on my windows host I have a Spring Boot application running at port 10090:
netstat -an | grep 10090
  TCP    0.0.0.0:10090          0.0.0.0:0              LISTENING
  TCP    [::]:10090             [::]:0                 LISTENING
  TCP    [::1]:53110            [::1]:10090            TIME_WAIT
  TCP    [::1]:53123            [::1]:10090            TIME_WAIT
  TCP    [::1]:53126            [::1]:10090            TIME_WAIT

and I can also see the nginx container
netstat -an | grep 80
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING
  TCP    [::]:80                [::]:0                 LISTENING
  TCP    [::1]:80               [::]:0                 LISTENING


If in browser you type "localhost" you should get nginx welcome page (at port 80, default)

Now log into container:
docker exec -it webserver sh

from the container you can connect to
curl host.docker.internal
curl host.docker.internal:10090
they both work, because they "resolve to the internal IP address used by the host"
On my Windows host, if I type "ipconfig" I see that I have
Ethernet adapter vEthernet (WSL): 172.28.176.1
Ethernet adapter Ethernet: 192.168.0.248
If I try:
curl 172.28.176.1:10090
curl 192.168.0.248:10090
they both work on both host and container, but the first is a lot more responsive.
This proves that from container you can access a service running on host.

References:

http://man.hubwiz.com/docset/Docker.docset/Contents/Resources/Documents/docs.docker.com/docker-for-windows/networking.html

NB: besides host.docker.internal , also docker.for.win.localhost can be used, but they have different values (which?)

Saturday, March 11, 2023

Intellij Java remote debug with SSH tunnel

This is the simplest explanation how to do it:
https://arjon.es/2014/remote-debug-of-a-java-app-using-ssh-tunneling-without-opening-server-ports/ (it is a bit confusing, as is uses localhost for both remote and local)
and
https://www.revsys.com/writings/quicktips/ssh-tunnel.html which clearly runs the ssh command locally forwarding to remote and highlights the role of -N parameter)
also worth reading:
https://www.jetbrains.com/help/idea/remote-debugging-via-ssh-tunnel.html#troubleshooting this is about PHP debugging

SSH tunneling explained visually https://www.youtube.com/watch?v=N8f5zv9UUMI

this command does the trick:
ssh -f user@personal-server.com -L 9999:personal-server.com:9999 -N

Chrome Developer Tools devtools

2 interesting crash courses : https://www.youtube.com/watch?v=gTVpBbFWry8
https://www.youtube.com/watch?v=gTVpBbFWry8

Monday, January 9, 2023

Spring DispatcherServlet mappings debugging

clone the project in https://spring.io/guides/gs/actuator-service/ that is https://github.com/spring-guides/gs-actuator-service.git , and start the application in complete folder

add in application.properties:

management.endpoints.web.exposure.include=*
logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping: TRACE
logging.level.org.springframework.web: DEBUG

( see https://stackoverflow.com/a/54636087/651288 )

See also https://www.baeldung.com/spring-boot-logging and https://www.baeldung.com/spring-boot-actuator-enable-endpoints This is what I get:

D:\pierre\Java\jdk-17.0.5\bin\java.exe -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2022.2.3\lib\idea_rt.jar=61385:D:\Program Files\JetBrains\IntelliJ IDEA 2022.2.3\bin" -Dfile.encoding=UTF-8 -classpath D:\pierre\github\gs-actuator-service\complete\build\classes\java\main;D:\pierre\github\gs-actuator-service\complete\build\resources\main;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-actuator\3.0.0\bc775ac676465e9da4d191d5b8378e1391fc708c\spring-boot-starter-actuator-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-web\3.0.0\5dd6c38f60b915dce2c4a340f4ea68f2e52306f8\spring-boot-starter-web-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter\3.0.0\18c02ab19529d866723b40c03021cd731c3edb50\spring-boot-starter-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-actuator-autoconfigure\3.0.0\4d437f988e82692b969fdec4a43002d8857e1c01\spring-boot-actuator-autoconfigure-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\io.micrometer\micrometer-core\1.10.2\ca69ca5d4d1fea81ec5f3e05bc159db4e3c87e1\micrometer-core-1.10.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\io.micrometer\micrometer-observation\1.10.2\5b63205c0e9f3acf4b84f852ea707f9f9fffda6f\micrometer-observation-1.10.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-json\3.0.0\beb1a175ad3cdec82ebd36dd1ddd08a9738a2d86\spring-boot-starter-json-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework\spring-webmvc\6.0.2\cf96960288ba6a95da3488b6d255803c50fa1927\spring-webmvc-6.0.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework\spring-web\6.0.2\39dde8bfcc9074af0fcec924ca7465cb90eb25d4\spring-web-6.0.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-tomcat\3.0.0\cbaf1a7a69a4a4126896bc397c14b9281634f8e7\spring-boot-starter-tomcat-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-autoconfigure\3.0.0\11c57cfd7a6c6ef2cf16cc91c4d9173f6ab16dd2\spring-boot-autoconfigure-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot\3.0.0\dcf84aaccdb294b8fe53a92b57efecf16708eb2c\spring-boot-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-logging\3.0.0\af37a21b0be9c0c8cd11e3f8a3330b314af639d3\spring-boot-starter-logging-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\jakarta.annotation\jakarta.annotation-api\2.1.1\48b9bda22b091b1f48b13af03fe36db3be6e1ae3\jakarta.annotation-api-2.1.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework\spring-core\6.0.2\43f8a6c8b522181d507705aac0e1f1b1e81e7701\spring-core-6.0.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.yaml\snakeyaml\1.33\2cd0a87ff7df953f810c344bdf2fe3340b954c69\snakeyaml-1.33.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-actuator\3.0.0\647ddeb370cfc79329663b28edc32e1fbf6ca10f\spring-boot-actuator-3.0.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\io.micrometer\micrometer-commons\1.10.2\3a97e1874b8ca9c1c08f67d58bf7d567bb748601\micrometer-commons-1.10.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jsr310\2.14.1\f24e8cb1437e05149b7a3049ebd6700f42e664b1\jackson-datatype-jsr310-2.14.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.module\jackson-module-parameter-names\2.14.1\2e05a86dba3d4b05074b6a313c4d5b7ff844c8dd\jackson-module-parameter-names-2.14.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.datatype\jackson-datatype-jdk8\2.14.1\da194197d187bf24a8699514344ebf0abd7c342a\jackson-datatype-jdk8-2.14.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-databind\2.14.1\268524b9056cae1211b9f1f52560ef19347f4d17\jackson-databind-2.14.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework\spring-context\6.0.2\649dc1c9947da39a0d4e3869d61e7270489aaa25\spring-context-6.0.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aop\6.0.2\fe73295dd65e6b2f53986622c1e622cd3d09aa03\spring-aop-6.0.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework\spring-beans\6.0.2\87ded7c3d973ec0bfebe0b6511375ffebe178ae5\spring-beans-6.0.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework\spring-expression\6.0.2\89687daffb67231f6be7783775c1f0d46f4541fe\spring-expression-6.0.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-websocket\10.1.1\c5a12c16c7ae8dc39f6dad01e486f6c76ef10343\tomcat-embed-websocket-10.1.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-core\10.1.1\d3bbf1c2c71a79c5c472090c31e3c28efea5304e\tomcat-embed-core-10.1.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.apache.tomcat.embed\tomcat-embed-el\10.1.1\a5282bdc29026cacc8e2941b53c78621beed4c7\tomcat-embed-el-10.1.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-classic\1.4.5\28e7dc0b208d6c3f15beefd73976e064b4ecfa9b\logback-classic-1.4.5.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-to-slf4j\2.19.0\30f4812e43172ecca5041da2cb6b965cc4777c19\log4j-to-slf4j-2.19.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.slf4j\jul-to-slf4j\2.0.4\37418ab81680501a3a1e58e04d1341a5efe1c162\jul-to-slf4j-2.0.4.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jcl\6.0.2\5eec2672aab8f80a54ea9047938884813c9eeec8\spring-jcl-6.0.2.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-annotations\2.14.1\2a6ad504d591a7903ffdec76b5b7252819a2d162\jackson-annotations-2.14.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-core\2.14.1\7a07bc535ccf0b7f6929c4d0f2ab9b294ef7c4a3\jackson-core-2.14.1.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-core\1.4.5\e9bb2ea70f84401314da4300343b0a246c8954da\logback-core-1.4.5.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\2.0.4\30d5eb5360bd113ce96f9e49e3431993bbf1b247\slf4j-api-2.0.4.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.19.0\ea1b37f38c327596b216542bc636cfdc0b8036fa\log4j-api-2.19.0.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.hdrhistogram\HdrHistogram\2.1.12\6eb7552156e0d517ae80cc2247be1427c8d90452\HdrHistogram-2.1.12.jar;C:\Users\pierl\.gradle\caches\modules-2\files-2.1\org.latencyutils\LatencyUtils\2.0.3\769c0b82cb2421c8256300e907298a9410a2a3d3\LatencyUtils-2.0.3.jar com.example.actuatorservice.HelloWorldApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.0)

2023-01-09T14:08:30.732+01:00  INFO 17492 --- [           main] c.e.a.HelloWorldApplication              : Starting HelloWorldApplication using Java 17.0.5 with PID 17492 (D:\pierre\github\gs-actuator-service\complete\build\classes\java\main started by pierl in D:\pierre\github\gs-actuator-service)
2023-01-09T14:08:30.737+01:00  INFO 17492 --- [           main] c.e.a.HelloWorldApplication              : No active profile set, falling back to 1 default profile: "default"
2023-01-09T14:08:32.077+01:00  INFO 17492 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9000 (http)
2023-01-09T14:08:32.091+01:00  INFO 17492 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-01-09T14:08:32.091+01:00  INFO 17492 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.1]
2023-01-09T14:08:32.201+01:00  INFO 17492 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-01-09T14:08:32.202+01:00  INFO 17492 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1402 ms
2023-01-09T14:08:32.318+01:00 DEBUG 17492 --- [           main] o.s.w.f.ServerHttpObservationFilter      : Filter 'serverHttpObservationFilter' configured for use
2023-01-09T14:08:32.490+01:00 DEBUG 17492 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice
2023-01-09T14:08:32.580+01:00 TRACE 17492 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 
	c.e.a.HelloWorldController:
	{GET [/hello-world]}: sayHello(String)
2023-01-09T14:08:32.583+01:00 TRACE 17492 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 
	o.s.b.a.w.s.e.BasicErrorController:
	{ [/error]}: error(HttpServletRequest)
	{ [/error], produces [text/html]}: errorHtml(HttpServletRequest,HttpServletResponse)
2023-01-09T14:08:32.586+01:00 DEBUG 17492 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 3 mappings in 'requestMappingHandlerMapping'
2023-01-09T14:08:32.604+01:00 DEBUG 17492 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Patterns [/webjars/**, /**] in 'resourceHandlerMapping'
2023-01-09T14:08:32.612+01:00 DEBUG 17492 --- [           main] .m.m.a.ExceptionHandlerExceptionResolver : ControllerAdvice beans: 0 @ExceptionHandler, 1 ResponseBodyAdvice
2023-01-09T14:08:32.930+01:00  INFO 17492 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9000 (http) with context path ''
2023-01-09T14:08:33.007+01:00  INFO 17492 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9001 (http)
2023-01-09T14:08:33.008+01:00  INFO 17492 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-01-09T14:08:33.008+01:00  INFO 17492 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.1]
2023-01-09T14:08:33.033+01:00  INFO 17492 --- [           main] o.a.c.c.C.[Tomcat-1].[localhost].[/]     : Initializing Spring embedded WebApplicationContext
2023-01-09T14:08:33.034+01:00  INFO 17492 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 100 ms
2023-01-09T14:08:33.054+01:00  INFO 17492 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 13 endpoint(s) beneath base path '/actuator'
2023-01-09T14:08:33.075+01:00 TRACE 17492 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 
	o.s.b.a.a.w.s.ManagementErrorEndpoint:
	{ [/error]}: invoke(ServletWebRequest)
2023-01-09T14:08:33.075+01:00 DEBUG 17492 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : 1 mappings in 'requestMappingHandlerMapping'
2023-01-09T14:08:33.080+01:00 DEBUG 17492 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Patterns [/webjars/**, /**] in 'resourceHandlerMapping'
2023-01-09T14:08:33.084+01:00 DEBUG 17492 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice
2023-01-09T14:08:33.093+01:00  INFO 17492 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9001 (http) with context path ''
2023-01-09T14:08:33.108+01:00  INFO 17492 --- [           main] c.e.a.HelloWorldApplication              : Started HelloWorldApplication in 2.927 seconds (process running for 3.697)


http://localhost:9001/actuator/mappings this will give also all your endpoints. See https://docs.spring.io/spring-boot/docs/2.1.11.RELEASE/reference/html/production-ready-endpoints.html for all possoble actuators. And here https://www.baeldung.com/spring-boot-actuators for more coverage on actuators.

When you actually hit an endpoint, like http://localhost:9001/actuator/mappings , this is what you see:

2023-01-09T14:35:33.297+01:00 DEBUG 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/actuator/mappings", parameters={}
2023-01-09T14:35:33.341+01:00  INFO 23248 --- [0.1-9001-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-01-09T14:35:33.342+01:00  INFO 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-01-09T14:35:33.342+01:00 DEBUG 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Detected StandardServletMultipartResolver
2023-01-09T14:35:33.342+01:00 DEBUG 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Detected AcceptHeaderLocaleResolver
2023-01-09T14:35:33.342+01:00 DEBUG 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Detected FixedThemeResolver
2023-01-09T14:35:33.343+01:00 DEBUG 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator@3f1a2baf
2023-01-09T14:35:33.343+01:00 DEBUG 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.servlet.support.SessionFlashMapManager@50211373
2023-01-09T14:35:33.343+01:00 DEBUG 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
2023-01-09T14:35:33.343+01:00  INFO 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2023-01-09T14:35:33.355+01:00 DEBUG 23248 --- [0.1-9001-exec-1] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/vnd.spring-boot.actuator.v3+json;q=0.8', given [text/html, application/xhtml+xml, image/avif, image/webp, application/xml;q=0.9, */*;q=0.8] and supported [application/vnd.spring-boot.actuator.v3+json, application/vnd.spring-boot.actuator.v2+json, application/json]
2023-01-09T14:35:33.357+01:00 DEBUG 23248 --- [0.1-9001-exec-1] m.m.a.RequestResponseBodyMethodProcessor : Writing [org.springframework.boot.actuate.web.mappings.MappingsEndpoint$ApplicationMappingsDescriptor@69771f5 (truncated)...]
2023-01-09T14:35:33.388+01:00 DEBUG 23248 --- [0.1-9001-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

but it's always best to check also Tomcat logs

Sunday, January 8, 2023

React Router explained

https://www.youtube.com/watch?v=Ul3y1LXxzdU best tutorial ever - much better than official documentation https://reactrouter.com/en/main

Wednesday, January 4, 2023