Merge branch 'master' into monitoring

This commit is contained in:
Benjamin Huo
2019-05-14 11:22:56 +08:00
committed by GitHub
721 changed files with 87960 additions and 53512 deletions

View File

@@ -18,11 +18,7 @@
package controller
import (
"kubesphere.io/kubesphere/pkg/controller/clusterrolebinding"
)
func init() {
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
AddToManagerFuncs = append(AddToManagerFuncs, clusterrolebinding.Add)
//AddToManagerFuncs = append(AddToManagerFuncs, clusterrolebinding.Add)
}

View File

@@ -18,9 +18,7 @@
package controller
import (
"kubesphere.io/kubesphere/pkg/controller/namespace"
)
import "kubesphere.io/kubesphere/pkg/controller/namespace"
func init() {
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.

View File

@@ -21,9 +21,6 @@ import (
)
func init() {
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
//AddToManagerFuncs = append(AddToManagerFuncs, strategy.Add)
// Add application to manager functions
AddToManagerFuncs = append(AddToManagerFuncs, application.Add)

View File

@@ -0,0 +1,262 @@
package application
import (
"fmt"
applicationclient "github.com/kubernetes-sigs/application/pkg/client/clientset/versioned"
applicationinformers "github.com/kubernetes-sigs/application/pkg/client/informers/externalversions/app/v1beta1"
applicationlister "github.com/kubernetes-sigs/application/pkg/client/listers/app/v1beta1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
informersv1 "k8s.io/client-go/informers/apps/v1"
coreinformers "k8s.io/client-go/informers/core/v1"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
listersv1 "k8s.io/client-go/listers/apps/v1"
corelisters "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/util/metrics"
servicemeshinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions/servicemesh/v1alpha2"
servicemeshlisters "kubesphere.io/kubesphere/pkg/client/listers/servicemesh/v1alpha2"
"kubesphere.io/kubesphere/pkg/controller/virtualservice/util"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
"time"
)
const (
// maxRetries is the number of times a service will be retried before it is dropped out of the queue.
// With the current rate-limiter in use (5ms*2^(maxRetries-1)) the following numbers represent the
// sequence of delays between successive queuings of a service.
//
// 5ms, 10ms, 20ms, 40ms, 80ms, 160ms, 320ms, 640ms, 1.3s, 2.6s, 5.1s, 10.2s, 20.4s, 41s, 82s
maxRetries = 15
)
var log = logf.Log.WithName("application-controller")
type ApplicationController struct {
client clientset.Interface
applicationClient applicationclient.Interface
eventBroadcaster record.EventBroadcaster
eventRecorder record.EventRecorder
applicationLister applicationlister.ApplicationLister
applicationSynced cache.InformerSynced
serviceLister corelisters.ServiceLister
serviceSynced cache.InformerSynced
deploymentLister listersv1.DeploymentLister
deploymentSynced cache.InformerSynced
statefulSetLister listersv1.StatefulSetLister
statefulSetSynced cache.InformerSynced
strategyLister servicemeshlisters.StrategyLister
strategySynced cache.InformerSynced
servicePolicyLister servicemeshlisters.ServicePolicyLister
servicePolicySynced cache.InformerSynced
queue workqueue.RateLimitingInterface
workerLoopPeriod time.Duration
}
func NewApplicationController(serviceInformer coreinformers.ServiceInformer,
deploymentInformer informersv1.DeploymentInformer,
statefulSetInformer informersv1.StatefulSetInformer,
strategyInformer servicemeshinformers.StrategyInformer,
servicePolicyInformer servicemeshinformers.ServicePolicyInformer,
applicationInformer applicationinformers.ApplicationInformer,
client clientset.Interface,
applicationClient applicationclient.Interface) *ApplicationController {
broadcaster := record.NewBroadcaster()
broadcaster.StartLogging(func(format string, args ...interface{}) {
log.Info(fmt.Sprintf(format, args))
})
broadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: client.CoreV1().Events("")})
recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "application-controller"})
if client != nil && client.CoreV1().RESTClient().GetRateLimiter() != nil {
metrics.RegisterMetricAndTrackRateLimiterUsage("virtualservice_controller", client.CoreV1().RESTClient().GetRateLimiter())
}
v := &ApplicationController{
client: client,
applicationClient: applicationClient,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "application"),
workerLoopPeriod: time.Second,
}
v.deploymentLister = deploymentInformer.Lister()
v.deploymentSynced = deploymentInformer.Informer().HasSynced
deploymentInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: v.enqueueObject,
DeleteFunc: v.enqueueObject,
})
v.statefulSetLister = statefulSetInformer.Lister()
v.statefulSetSynced = statefulSetInformer.Informer().HasSynced
statefulSetInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: v.enqueueObject,
DeleteFunc: v.enqueueObject,
})
v.serviceLister = serviceInformer.Lister()
v.serviceSynced = serviceInformer.Informer().HasSynced
serviceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: v.enqueueObject,
DeleteFunc: v.enqueueObject,
})
v.strategyLister = strategyInformer.Lister()
v.strategySynced = strategyInformer.Informer().HasSynced
strategyInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: v.enqueueObject,
DeleteFunc: v.enqueueObject,
})
v.servicePolicyLister = servicePolicyInformer.Lister()
v.servicePolicySynced = servicePolicyInformer.Informer().HasSynced
servicePolicyInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: v.enqueueObject,
DeleteFunc: v.enqueueObject,
})
v.applicationLister = applicationInformer.Lister()
v.applicationSynced = applicationInformer.Informer().HasSynced
v.eventBroadcaster = broadcaster
v.eventRecorder = recorder
return v
}
func (v *ApplicationController) Start(stopCh <-chan struct{}) error {
v.Run(5, stopCh)
return nil
}
func (v *ApplicationController) Run(workers int, stopCh <-chan struct{}) {
defer utilruntime.HandleCrash()
defer v.queue.ShutDown()
log.Info("starting application controller")
defer log.Info("shutting down application controller")
if !controller.WaitForCacheSync("application-controller", stopCh, v.deploymentSynced, v.statefulSetSynced, v.serviceSynced, v.strategySynced, v.servicePolicySynced, v.applicationSynced) {
return
}
for i := 0; i < workers; i++ {
go wait.Until(v.worker, v.workerLoopPeriod, stopCh)
}
<-stopCh
}
func (v *ApplicationController) worker() {
for v.processNextWorkItem() {
}
}
func (v *ApplicationController) processNextWorkItem() bool {
eKey, quit := v.queue.Get()
if quit {
return false
}
defer v.queue.Done(eKey)
err := v.syncApplication(eKey.(string))
v.handleErr(err, eKey)
return true
}
func (v *ApplicationController) syncApplication(key string) error {
startTime := time.Now()
namespace, name, err := cache.SplitMetaNamespaceKey(key)
if err != nil {
log.Error(err, "not a valid controller key", "key", key)
return err
}
defer func() {
log.V(4).Info("Finished updating application.", "namespace", namespace, "name", name, "duration", time.Since(startTime))
}()
application, err := v.applicationLister.Applications(namespace).Get(name)
if err != nil {
if errors.IsNotFound(err) {
// application has been deleted
return nil
}
log.Error(err, "get application failed")
}
annotations := application.GetAnnotations()
annotations["kubesphere.io/last-updated"] = time.Now().String()
application.SetAnnotations(annotations)
_, err = v.applicationClient.AppV1beta1().Applications(namespace).Update(application)
if err != nil {
if errors.IsNotFound(err) {
log.V(4).Info("application has been deleted during update")
return nil
}
log.Error(err, "failed to update application", "namespace", namespace, "name", name)
return err
}
return nil
}
func (v *ApplicationController) enqueueObject(obj interface{}) {
var resource = obj.(metav1.Object)
if resource.GetLabels() == nil || !util.IsApplicationComponent(resource.GetLabels()) {
return
}
applicationName := util.GetApplictionName(resource.GetLabels())
if len(applicationName) > 0 {
key := resource.GetNamespace() + "/" + applicationName
v.queue.Add(key)
}
}
func (v *ApplicationController) handleErr(err error, key interface{}) {
if err != nil {
v.queue.Forget(key)
return
}
if v.queue.NumRequeues(key) < maxRetries {
log.V(2).Info("Error syncing virtualservice for service retrying.", "key", key, "error", err)
v.queue.AddRateLimited(key)
return
}
log.V(4).Info("Dropping service out of the queue.", "key", key, "error", err)
v.queue.Forget(key)
utilruntime.HandleError(err)
}

View File

@@ -0,0 +1 @@
package application

View File

@@ -332,9 +332,9 @@ func (v *DestinationRuleController) syncService(key string) error {
}
if createDestinationRule {
_, err = v.destinationRuleClient.NetworkingV1alpha3().DestinationRules(namespace).Create(newDestinationRule)
newDestinationRule, err = v.destinationRuleClient.NetworkingV1alpha3().DestinationRules(namespace).Create(newDestinationRule)
} else {
_, err = v.destinationRuleClient.NetworkingV1alpha3().DestinationRules(namespace).Update(newDestinationRule)
newDestinationRule, err = v.destinationRuleClient.NetworkingV1alpha3().DestinationRules(namespace).Update(newDestinationRule)
}
if err != nil {

View File

@@ -18,6 +18,7 @@ const (
// resource with these following labels considered as part of servicemesh
var ApplicationLabels = [...]string{
ApplicationNameLabel,
ApplicationVersionLabel,
AppLabel,
}
@@ -32,6 +33,14 @@ func NormalizeVersionName(version string) string {
return version
}
func GetApplictionName(lbs map[string]string) string {
if name, ok := lbs[ApplicationNameLabel]; ok {
return name
}
return ""
}
func GetComponentName(meta *metav1.ObjectMeta) string {
if len(meta.Labels[AppLabel]) > 0 {
return meta.Labels[AppLabel]

View File

@@ -387,9 +387,9 @@ func (v *VirtualServiceController) syncService(key string) error {
}
if createVirtualService {
_, err = v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Create(newVirtualService)
newVirtualService, err = v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Create(newVirtualService)
} else {
_, err = v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Update(newVirtualService)
newVirtualService, err = v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Update(newVirtualService)
}
if err != nil {

View File

@@ -19,9 +19,11 @@
package routers
import (
"fmt"
"github.com/golang/glog"
"io/ioutil"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"sort"
@@ -48,6 +50,37 @@ const (
SIDECAR_INJECT = "sidecar.istio.io/inject"
)
var routerTemplates map[string]runtime.Object
// Load yamls
func init() {
yamls, err := LoadYamls()
routerTemplates = make(map[string]runtime.Object, 2)
if err != nil {
glog.Error(err)
return
}
for _, f := range yamls {
decode := scheme.Codecs.UniversalDeserializer().Decode
obj, _, err := decode([]byte(f), nil, nil)
if err != nil {
glog.Error(err)
continue
}
switch obj.(type) {
case *corev1.Service:
routerTemplates["SERVICE"] = obj
case *extensionsv1beta1.Deployment:
routerTemplates["DEPLOYMENT"] = obj
}
}
}
// get master node ip, if there are multiple master nodes,
// choose first one according by their names alphabetically
func getMasterNodeIp() string {
@@ -115,6 +148,12 @@ func GetAllRouters() ([]*corev1.Service, error) {
// Get router from a namespace
func GetRouter(namespace string) (*corev1.Service, error) {
service, err := getRouterService(namespace)
addLoadBalancerIp(service)
return service, err
}
func getRouterService(namespace string) (*corev1.Service, error) {
serviceName := constants.IngressControllerPrefix + namespace
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
@@ -127,8 +166,6 @@ func GetRouter(namespace string) (*corev1.Service, error) {
glog.Error(err)
return nil, err
}
addLoadBalancerIp(service)
return service, nil
}
@@ -163,12 +200,6 @@ func LoadYamls() ([]string, error) {
// Create a ingress controller in a namespace
func CreateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
k8sClient := k8s.Client()
var router *corev1.Service
yamls, err := LoadYamls()
injectSidecar := false
if enabled, ok := annotations[SERVICEMESH_ENABLED]; ok {
if enabled == "true" {
@@ -176,74 +207,17 @@ func CreateRouter(namespace string, routerType corev1.ServiceType, annotations m
}
}
err := createOrUpdateRouterWorkload(namespace, routerType == corev1.ServiceTypeLoadBalancer, injectSidecar)
if err != nil {
glog.Error(err)
return nil, err
}
for _, f := range yamls {
decode := scheme.Codecs.UniversalDeserializer().Decode
obj, _, err := decode([]byte(f), nil, nil)
if err != nil {
glog.Error(err)
return router, err
}
switch obj.(type) {
case *corev1.Service:
service := obj.(*corev1.Service)
service.SetAnnotations(annotations)
service.Spec.Type = routerType
service.Name = constants.IngressControllerPrefix + namespace
// Add project selector
service.Labels["project"] = namespace
service.Spec.Selector["project"] = namespace
service, err := k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Create(service)
if err != nil {
glog.Error(err)
return nil, err
}
router = service
case *extensionsv1beta1.Deployment:
deployment := obj.(*extensionsv1beta1.Deployment)
deployment.Name = constants.IngressControllerPrefix + namespace
// Add project label
deployment.Spec.Selector.MatchLabels["project"] = namespace
deployment.Spec.Template.Labels["project"] = namespace
if injectSidecar {
if deployment.Spec.Template.Annotations == nil {
deployment.Spec.Template.Annotations = make(map[string]string, 0)
}
deployment.Spec.Template.Annotations[SIDECAR_INJECT] = "true"
}
// Isolate namespace
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--watch-namespace="+namespace)
// Choose self as master
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name)
if routerType == corev1.ServiceTypeLoadBalancer {
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace)
} else {
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address")
}
deployment, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Create(deployment)
if err != nil {
glog.Error(err)
}
default:
//glog.Info("Default resource")
}
router, err := createRouterService(namespace, routerType, annotations)
if err != nil {
glog.Error(err)
_ = deleteRouterWorkload(namespace)
return nil, err
}
addLoadBalancerIp(router)
@@ -253,10 +227,85 @@ func CreateRouter(namespace string, routerType corev1.ServiceType, annotations m
// DeleteRouter is used to delete ingress controller related resources in namespace
// It will not delete ClusterRole resource cause it maybe used by other controllers
func DeleteRouter(namespace string) (*corev1.Service, error) {
err := deleteRouterWorkload(namespace)
if err != nil {
glog.Error(err)
}
router, err := deleteRouterService(namespace)
if err != nil {
glog.Error(err)
return router, err
}
return router, nil
}
func createRouterService(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
obj, ok := routerTemplates["SERVICE"]
if !ok {
glog.Error("service template not loaded")
return nil, fmt.Errorf("service template not loaded")
}
k8sClient := k8s.Client()
var err error
var router *corev1.Service
service := obj.(*corev1.Service)
service.SetAnnotations(annotations)
service.Spec.Type = routerType
service.Name = constants.IngressControllerPrefix + namespace
// Add project selector
service.Labels["project"] = namespace
service.Spec.Selector["project"] = namespace
service, err := k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Create(service)
if err != nil {
glog.Error(err)
return nil, err
}
return service, nil
}
func updateRouterService(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
k8sClient := k8s.Client()
service, err := getRouterService(namespace)
if err != nil {
glog.Error(err, "get router failed")
return service, err
}
service.Spec.Type = routerType
originalAnnotations := service.GetAnnotations()
for key, val := range annotations {
originalAnnotations[key] = val
}
service.SetAnnotations(originalAnnotations)
service, err = k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Update(service)
return service, err
}
func deleteRouterService(namespace string) (*corev1.Service, error) {
service, err := getRouterService(namespace)
if err != nil {
glog.Error(err)
return service, err
}
k8sClient := k8s.Client()
// delete controller service
serviceName := constants.IngressControllerPrefix + namespace
@@ -265,11 +314,98 @@ func DeleteRouter(namespace string) (*corev1.Service, error) {
err = k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Delete(serviceName, &deleteOptions)
if err != nil {
glog.Error(err)
return service, err
}
return service, nil
}
func createOrUpdateRouterWorkload(namespace string, publishService bool, servicemeshEnabled bool) error {
obj, ok := routerTemplates["DEPLOYMENT"]
if !ok {
glog.Error("Deployment template file not loaded")
return fmt.Errorf("deployment template file not loaded")
}
deployName := constants.IngressControllerPrefix + namespace
k8sClient := k8s.Client()
deployment, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Get(deployName, meta_v1.GetOptions{})
createDeployment := true
if err != nil {
if errors.IsNotFound(err) {
deployment = obj.(*extensionsv1beta1.Deployment)
deployment.Name = constants.IngressControllerPrefix + namespace
// Add project label
deployment.Spec.Selector.MatchLabels["project"] = namespace
deployment.Spec.Template.Labels["project"] = namespace
// Isolate namespace
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--watch-namespace="+namespace)
// Choose self as master
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name)
}
} else {
createDeployment = false
for i := range deployment.Spec.Template.Spec.Containers {
if deployment.Spec.Template.Spec.Containers[i].Name == "nginx-ingress-controller" {
var args []string
for j := range deployment.Spec.Template.Spec.Containers[i].Args {
if strings.HasPrefix("--publish-service", deployment.Spec.Template.Spec.Containers[i].Args[j]) ||
strings.HasPrefix("--report-node-internal-ip-address", deployment.Spec.Template.Spec.Containers[i].Args[j]) {
continue
}
args = append(args, deployment.Spec.Template.Spec.Containers[i].Args[j])
}
deployment.Spec.Template.Spec.Containers[i].Args = args
}
}
}
if deployment.Spec.Template.Annotations == nil {
deployment.Spec.Template.Annotations = make(map[string]string, 0)
}
if servicemeshEnabled {
deployment.Spec.Template.Annotations[SIDECAR_INJECT] = "true"
} else {
deployment.Spec.Template.Annotations[SIDECAR_INJECT] = "false"
}
if publishService {
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace)
} else {
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address")
}
if createDeployment {
deployment, err = k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Create(deployment)
} else {
deployment, err = k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Update(deployment)
}
if err != nil {
glog.Error(err)
return err
}
return nil
}
func deleteRouterWorkload(namespace string) error {
k8sClient := k8s.Client()
deleteOptions := meta_v1.DeleteOptions{}
// delete controller deployment
deploymentName := constants.IngressControllerPrefix + namespace
err = k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Delete(deploymentName, &deleteOptions)
err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Delete(deploymentName, &deleteOptions)
if err != nil {
glog.Error(err)
}
@@ -280,45 +416,50 @@ func DeleteRouter(namespace string) (*corev1.Service, error) {
"app": "kubesphere",
"component": "ks-router",
"tier": "backend",
"project": deploymentName,
"project": namespace,
})
replicaSetLister := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
replicaSets, err := replicaSetLister.ReplicaSets(constants.IngressControllerNamespace).List(selector)
if err == nil {
if err != nil {
glog.Error(err)
}
for i := range replicaSets {
err = k8sClient.AppsV1().ReplicaSets(constants.IngressControllerNamespace).Delete(replicaSets[i].Name, &deleteOptions)
glog.Error(err)
if err != nil {
glog.Error(err)
}
}
return router, nil
return nil
}
// Update Ingress Controller Service, change type from NodePort to Loadbalancer or vice versa.
// Update Ingress Controller Service, change type from NodePort to loadbalancer or vice versa.
func UpdateRouter(namespace string, routerType corev1.ServiceType, annotations map[string]string) (*corev1.Service, error) {
var router *corev1.Service
router, err := GetRouter(namespace)
router, err := getRouterService(namespace)
if err != nil {
glog.Error(err)
return router, nil
return router, err
}
router, err = DeleteRouter(namespace)
enableServicemesh := annotations[SERVICEMESH_ENABLED] == "true"
err = createOrUpdateRouterWorkload(namespace, routerType == corev1.ServiceTypeLoadBalancer, enableServicemesh)
if err != nil {
glog.Error(err)
return router, err
}
newRouter, err := updateRouterService(namespace, routerType, annotations)
if err != nil {
glog.Error(err)
return newRouter, err
}
router, err = CreateRouter(namespace, routerType, annotations)
if err != nil {
glog.Error(err)
}
return router, nil
return newRouter, nil
}

24
pkg/server/server.go Normal file
View File

@@ -0,0 +1,24 @@
package server
import (
"bytes"
"fmt"
"github.com/golang/glog"
"net/http"
"runtime"
)
func LogStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter) {
var buffer bytes.Buffer
buffer.WriteString(fmt.Sprintf("recover from panic situation: - %v\r\n", panicReason))
for i := 2; ; i += 1 {
_, file, line, ok := runtime.Caller(i)
if !ok {
break
}
buffer.WriteString(fmt.Sprintf(" %s:%d\r\n", file, line))
}
glog.Error(buffer.String())
httpWriter.WriteHeader(http.StatusInternalServerError)
httpWriter.Write([]byte("recover from panic situation"))
}